home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / HTTP.C < prev    next >
Text File  |  1997-09-06  |  75KB  |  2,718 lines

  1. /* HTTP server
  2.  * A nearly complete rewrite, extensively expanded, based loosely on
  3.  * the HTTP server of Selcuk Ozturk <seost2+@pitt.edu> &
  4.  * <ashok@biochemistry.cwru.edu>, which were based on
  5.  * Chris McNeil's <cmcneil@mta.ca> Gopher server, which was based in
  6.  * part on fingerd.c
  7.  *
  8.  */
  9.  
  10. #include "global.h"
  11. #include "ctype.h"
  12. #include "commands.h"
  13. #ifdef MSDOS
  14. #include "hardware.h"
  15. #else
  16. #include <time.h>
  17. #include "mbuf.h"
  18. #include "socket.h"
  19. #include "session.h"
  20. #endif
  21. #if defined(HTTP) || defined(BROWSER)
  22. #include <sys/stat.h>
  23. #include "files.h"
  24. #include "mailbox.h"
  25. #include "smtp.h"
  26. #include "browser.h"
  27. #include "usock.h"
  28. #ifdef HTTPPBBS
  29. #include "domain.h"
  30. #include "bm.h"
  31. #endif
  32. #endif
  33. #ifdef STAT_HTTP
  34. #include "stats.h"
  35. #endif
  36.  
  37. #ifdef HTTP
  38.  
  39.  
  40. #if !defined(_lint)
  41. static char rcsid[] OPTIONAL = "$Id: http.c,v 1.35 1997/09/07 00:31:16 root Exp root $";
  42. #endif
  43.  
  44. #ifdef NO_SETENV
  45. char *setenv (char const *, char const *, int);
  46. #endif
  47.  
  48. #define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
  49. #define HTTP_TIME_FORMAT "%a, %d %b %Y %T GMT\n"
  50. #define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z"
  51. #define SIZEFMT_BYTES 0
  52. #define SIZEFMT_KMG 1
  53. #define SECS_IN_6MONTHS 15768000 /* seconds in 1/2 year */
  54.  
  55. static char entry[] = "<IMG SRC=\"/icons/%s.xbm\" ALT=\"%s\"> ";
  56. static char entry1[] = "<A HREF=\"/%s%s%s\">%-s</a>";
  57. static char entry2[] = "%2d-%s-%02d %02d:%02d %6dK\n";
  58. int HttpUsers = 0;
  59. static int Httpmax = 10;
  60. static int Httpsimc = 5;
  61. static int HttpSessions = 0;
  62. static int Httptdisc = 180;
  63. static int HTTPreferer = 1;
  64. static int HTTPagent = 1;
  65. static int HTTPcookie = 0;
  66. static int HTTPusecookies = 0;
  67. static int HTTPmisc = 1;
  68. static int HTTPpost = 1;
  69. static int HTTPexeccmd = 0;
  70. static int HTTPstatusURL = 1;
  71. #ifdef HTTPCGI
  72. static int HTTPexeccgi = 0;
  73. #endif
  74. #ifdef STRICT_HTTPCALL
  75. static int HTTPstrict = 0;
  76. #endif
  77. #ifdef HTTPPBBS
  78. static int HTTPexecbbs = 0;
  79. static int HTTPanonsend = 0;
  80. extern int32 MbAmprPerms;
  81. extern int32 MbNonAmprPerms;
  82. extern int32 MbHttpPerms;
  83. extern uint32 NonSecureAmpr;
  84. #endif
  85. extern time_t StartTime;
  86. #if 0
  87. static int HTTPscript = 0;
  88. #endif
  89. static FILE * HTTPsavedfp;
  90. static char *HTTPHostname;
  91. static char *HTTPFtpdir = NULLCHAR;
  92.  
  93. #ifdef MSDOS
  94. #define HTMLEXT    "htm"
  95. #else
  96. #define HTMLEXT "html"
  97. #endif
  98.  
  99. struct reqInfo {
  100.     int        port;
  101.     int        index;
  102. #if 0
  103.     int        response;
  104. #endif
  105.     int        qsize;        /* not used at the present */
  106.     int        sizefmt;
  107.     int        isvolatile;
  108. #ifdef HTTPPBBS
  109.     int        msgcount;
  110.     int        newmsgcount;
  111.     int        msgnum;
  112.     int        msgcurrent;
  113.     int        anony;
  114.     int        sock;
  115.     long        privs;
  116. #endif
  117.     char        *hostname;
  118.     char        *url;
  119.     char        *method;
  120.     char        *version;
  121.     char        *newcheck;
  122.     char        *from;
  123.     char        *referer;
  124.     char        *agent;
  125.     char        *passwd;
  126.     char        *dirname;
  127.     char        *ftpdirname;
  128.     char         *usetime;
  129.     char        *useerror;
  130.     char        *realm;
  131.     char        *cookie;
  132.     char        *rmtaddr;
  133.     char        *rmthost;
  134.     char        buf[PLINELEN + 16];
  135. #ifdef HTTPPBBS
  136.     char        *areaname;
  137.     char        *username;
  138.     struct mbx     *m;
  139.     char        *bbspath;
  140. #endif
  141. };
  142.  
  143.  
  144. struct secureURL    {
  145.     char         *url;
  146.     char         *pwfile;
  147.     char         *realm;
  148.     struct secureURL *next;
  149. };
  150. #define NULLSECUREURL ((struct secureURL *)0)
  151.  
  152. static struct secureURL *securedURLS = NULLSECUREURL;
  153.  
  154.  
  155. /* function prototypes */
  156. #ifdef HTTPCGI
  157. static void setup_cgi_variables (struct reqInfo *rq, char *name);
  158. #endif
  159. static int dohttpagent (int argc,char *argv[],void *p);
  160. static int dohttpexeccmd (int argc,char *argv[],void *p);
  161. static int dohttpstatusurl (int argc,char *argv[],void *p);
  162. static int dohttphostname (int argc,char *argv[],void *p);
  163. #ifdef HTTPCGI
  164. static int dohttpexeccgi (int argc,char *argv[],void *p);
  165. #endif
  166. #ifdef HTTPPBBS
  167. static int dohttpexecbbs (int argc,char *argv[],void *p);
  168. static int checkareaperms (struct reqInfo *rq);
  169. #endif
  170. static int dohttpmax (int argc,char *argv[],void *p);
  171. static int dohttpmisc (int argc,char *argv[],void *p);
  172. static int dohttppost (int argc,char *argv[],void *p);
  173. static int dohttpreferer (int argc,char *argv[],void *p);
  174. static int dohttpcookielog (int argc,char *argv[],void *p);
  175. static int dohttpcookies (int argc,char *argv[],void *p);
  176. static int dohttpsecure (int argc,char *argv[],void *p);
  177. #if 0
  178. static int dohttpscript (int argc,char *argv[],void *p);
  179. #endif
  180. static int dohttpsim (int argc,char *argv[],void *p);
  181. static int dohttpstatus (int argc,char *argv[],void *p);
  182. static int dohttptdisc (int argc,char *argv[],void *p);
  183. static int dohttpftpdir (int argc,char *argv[],void *p);
  184.  
  185. #ifdef STRICT_HTTPCALL
  186. static int dohttpstrict (int argc,char *argv[],void *p);
  187. #endif
  188.  
  189. static char *assigncookie (struct reqInfo *rq, time_t thetime);
  190. static void httpserv (int s,void *unused,void *p);
  191. static int mkwelcome (const char *Hdir,char *file, int ftpfile, const char *Ftpdir);
  192. static char * decode (char *string);
  193. static void httpHeaders (int type, const char *str, struct reqInfo *rq, int more, const char *realm);
  194. static void httpFileinfo (FILE *fp, struct reqInfo *rq, int thetype, char *vers);
  195. static void openHTTPlog (const char *name);
  196. static void closeHTTPlog (void);
  197. static int getmonth (char *cp);
  198. static int isnewer (time_t thetime,char *tmstr);
  199. static long countusage (const char *file, const char *basedir, int display, int increase);
  200. static void sendhtml (FILE *fp, int firstfile, struct reqInfo *rq);
  201. static void file_or_virtual (char *cp, char *newname, struct reqInfo *rq);
  202. static void send_size (int sizefmt,long size);
  203. static char *ht_time (time_t t,const char *fmt,int gmt);
  204. static char *gmt_ptime (time_t *thetime);
  205. static int addFile (const char *fname, int s);
  206. static struct secureURL *secured_url (struct reqInfo *rq);
  207. static int is_authorized (struct reqInfo *rq);
  208. static int http_authcheck (char *filename, char *username, char *pass);
  209.  
  210. #ifdef HTTPPBBS
  211. static void addUserFile (struct reqInfo *rq);
  212. static void addMsgFile (char *file, struct reqInfo *rq);
  213. static void doPBBScmd (struct reqInfo *rq, const char *cmdstring);
  214. static void doPBBScmd_init (struct reqInfo *rq);
  215. static void doPBBScmd_term (struct reqInfo *rq);
  216. static void doPBBScmd_exit (struct reqInfo *rq);
  217. static int dohttpanonsend (int argc,char *argv[],void *p);
  218. #endif
  219.  
  220. extern char *base64ToStr (char *b64);
  221. #ifdef ALLSERV
  222. extern char *getquote (void);
  223. #endif
  224.  
  225. /* HTTP Header lines sent or processed */
  226. #define HDR_TYPE        0
  227. #define HDR_LENGTH        1
  228. #define HDR_MIME        2
  229. #define HDR_SERVER        3
  230. #define HDR_LOCATION        4
  231. #define HDR_DATE        5
  232. #define HDR_MODIFIED        6
  233. #define HDR_SINCE        7
  234. #define HDR_REFERER        8
  235. #define HDR_AGENT        9
  236. #define HDR_FROM        10
  237. #define HDR_EXPIRES        11
  238. #define HDR_AUTHORIZE        12
  239. #define HDR_AUTHENTICATE    13
  240. #define HDR_COOKIE        14
  241.  
  242. static const char *HTTPHdrs[] = {
  243.     "Content-Type:",
  244.     "Content-Length:",
  245.     "MIME-version:",
  246.     "Server:",
  247.     "Location:",
  248.     "Date:",
  249.     "Last-Modified:",
  250.     "If-Modified-Since:",
  251.     "Referer:",
  252.     "User-Agent:",
  253.     "From:",
  254.     "Expires:",
  255.     "Authorization:",
  256.     "WWW-Authenticate:",
  257.     "Cookie:"
  258. };
  259.  
  260.  
  261. /* First component of MIME types */
  262.  
  263. static const char *CTypes1[] = {
  264.     "video/",
  265.     "text/",
  266.     "image/",
  267.     "audio/",
  268.     "application/"
  269. };
  270.  
  271.  
  272. /* Struct for looking up MIME types from file extensions */
  273. struct FileTypes {
  274.     const char *ext;
  275.     short type1;
  276.     const char *type2;
  277. };
  278.  
  279.  
  280. static struct FileTypes HTTPtypes[] = {
  281.     /* Other 'special' entries can be added in front of 'html',
  282.      * but care must be taken to make sure that the defines for
  283.      * HTTPbinary, HTTPplain, HTTPform, HTTPhtml and HTTPhtm are correct
  284.      * and that no entries with a 'NULLCHAR' ext come after 'html'
  285.      * except for the one that ends the table.
  286.      */
  287. #define HTTPbinary 0
  288.     { NULLCHAR,    4,    "octet-stream" },
  289. #define HTTPplain 1
  290.     { NULLCHAR,    1,    "plain" },
  291. #ifndef _lint
  292. #define HTTPform 2
  293. #endif
  294.     { NULLCHAR,    4,    "x-www-form-urlencoded" },
  295. #define HTTPhtml 3
  296.     { "html",    1,    "html" },
  297. #define HTTPhtm 4
  298.     { "htm",    1,    "html" },
  299.     /* the following can be in any order */
  300.     { "avi",    0,    "x-msvideo" },
  301.     { "qt",        0,    "quicktime" },
  302.     { "mov",    0,    "quicktime" },
  303.     { "mpeg",    0,    "mpeg" },
  304.     { "mpg",    0,    "mpeg" },
  305.     { "rtx",    1,    "richtext" },
  306.     { "xpm",    2,    "x-xpixmap" },
  307.     { "xbm",    2,    "x-xbitmap" },
  308.     { "rgb",    2,    "x-rgb" },
  309.     { "ppm",    2,    "x-portable-pixmap" },
  310.     { "pgm",    2,    "x-portable-graymap" },
  311.     { "pbm",    2,    "x-portable-bitmap" },
  312.     { "pnm",    2,    "x-portable-anymap" },
  313.     { "ras",    2,    "x-cmu-raster" },
  314.     { "tiff",    2,    "tiff" },
  315.     { "tif",    2,    "tiff" },
  316.     { "jpeg",    2,    "jpeg" },
  317.     { "jpg",    2,    "jpeg" },
  318.     { "gif",    2,    "gif" },
  319.     { "wav",    3,    "x-wav" },
  320.     { "aiff",    3,    "x-aiff" },
  321.     { "aif",    3,    "x-aiff" },
  322.     { "au",        3,    "basic" },
  323.     { "snd",    3,    "basic" },
  324.     { "tar",    4,    "x-tar" },
  325.     { "man",    4,    "x-trof-man" },
  326.     { "rtf",    4,    "rtf" },
  327.     { "eps",    4,    "postscript" },
  328.     { "ps",        4,    "postscript" },
  329.     { "sit",    4,    "x-stuffit" },
  330.     { "hqx",    4,    "mac-binhex40" },
  331.     { "fif",    4,    "fractals" },
  332.     { "zip",    4,    "x-zip" },
  333.     { "gz",        4,    "x-gzip" },
  334.     { "z",        4,    "x-compress" },
  335.     { NULLCHAR,    -1,    NULLCHAR }
  336. };
  337.  
  338.  
  339. /* Struct to keep tract of ports defined and their root directory */
  340.  
  341. #define MAXHTTPPORTS 10
  342. struct portsused {
  343.     int    port;
  344.     int    sock;
  345.     uint32    address;
  346.     char    *dirname;
  347.     char    *ftpdirname;
  348.     char    *hostname;
  349.     long    requests;
  350.     long    homehits;
  351.     long    stathits;
  352. #ifdef HTTPPBBS
  353.     long    bbshits;
  354. #endif
  355. };
  356. static struct portsused ports[MAXHTTPPORTS];
  357.  
  358.  
  359. #ifdef UNIX
  360. #define OS "Unix"
  361. #define WILDCARD "*"
  362. #else
  363. #define OS "MS-DOS"
  364. #define WILDCARD "*.*"
  365. #endif
  366.  
  367.  
  368.  
  369. static struct cmds Httpcmds[] = {
  370.     { "agentlogging",    dohttpagent,    0, 0, NULLCHAR },
  371. #ifdef HTTPPBBS
  372.     { "anonsend",        dohttpanonsend,    0, 0, NULLCHAR },
  373. #endif
  374.     { "cookielogging",    dohttpcookielog,0, 0, NULLCHAR },
  375. #ifdef HTTPPBBS
  376.     { "execbbs",        dohttpexecbbs,    0, 0, NULLCHAR },
  377. #endif
  378. #ifdef HTTPCGI
  379.     { "execcgi",        dohttpexeccgi,    0, 0, NULLCHAR },
  380. #endif
  381.     { "execcmd",        dohttpexeccmd,    0, 0, NULLCHAR },
  382.     { "ftpdir",        dohttpftpdir,    0, 0, NULLCHAR },
  383.     { "hostname",        dohttphostname, 0, 0, NULLCHAR },
  384.     { "maxcli",        dohttpmax,    0, 0, NULLCHAR },
  385.     { "misclogging",    dohttpmisc,    0, 0, NULLCHAR },
  386.     { "postlogging",    dohttppost,    0, 0, NULLCHAR },
  387.     { "refererlogging",    dohttpreferer,    0, 0, NULLCHAR },
  388. #if 0
  389.     { "script",        dohttpscript,    0, 0, NULLCHAR },
  390. #endif
  391.     { "secure",        dohttpsecure,    0, 0, NULLCHAR },
  392.     { "simult",        dohttpsim,    0, 0, NULLCHAR },
  393.     { "status",        dohttpstatus,    0, 0, NULLCHAR },
  394.     { "statusurl",        dohttpstatusurl,0, 0, NULLCHAR },
  395. #ifdef STRICT_HTTPCALL
  396.     { "strictcall",        dohttpstrict,    0, 0, NULLCHAR },
  397. #endif
  398.     { "tdisc",        dohttptdisc,    0, 0, NULLCHAR },
  399.     { "usecookies",        dohttpcookies,    0, 0, NULLCHAR },
  400.     { NULLCHAR,        NULL,        0, 0, NULLCHAR }
  401. };
  402.  
  403.  
  404.  
  405. int
  406. dohttp (int argc, char *argv[], void *p)
  407. {
  408.     return subcmd (Httpcmds, argc, argv, p);
  409. }
  410.  
  411.  
  412.  
  413. int
  414. dohttpstatus (int argc OPTIONAL, char *argv[], void *p)
  415. {
  416. int found = 0, k;
  417.  
  418.     for (k = 0; k < MAXHTTPPORTS; k++)    {
  419.         if (ports[k].port)    {
  420.             found++;
  421.             tprintf ("HTTP Server active on %s port #%-4d - %s\n", inet_ntoa (ports[k].address), ports[k].port, ports[k].dirname);
  422.         }
  423.     }
  424.     tputs ("    ");
  425.     if (!found)
  426.         tputs ("No");
  427.     else
  428.         tprintf ("%d", found);
  429.     tprintf (" HTTP Server%s %s active\n\n", (found == 1) ? "" : "s", (found == 1) ? "is" : "are");
  430.  
  431.     (void) dohttpagent (0, argv, p);
  432. #ifdef HTTPPBBS
  433.     (void) dohttpanonsend (0, argv, p);
  434. #endif
  435.     (void) dohttpcookielog (0, argv, p);
  436. #ifdef HTTPPBBS
  437.     (void) dohttpexecbbs (0, argv, p);
  438. #endif
  439. #ifdef HTTPCGI
  440.     (void) dohttpexeccgi (0, argv, p);
  441. #endif
  442.     (void) dohttpexeccmd (0, argv, p);
  443.     (void) dohttpftpdir (0, argv, p);
  444.     (void) dohttphostname (0, argv, p);
  445.     (void) dohttpmax (0, argv, p);
  446.     (void) dohttpmisc (0, argv, p);
  447.     (void) dohttppost (0, argv, p);
  448.     (void) dohttpreferer (0, argv, p);
  449.     (void) dohttpsecure (0, argv, p);
  450.     (void) dohttpsim (0, argv, p);
  451. #ifdef STRICT_HTTPCALL
  452.     (void) dohttpstrict (0, argv, p);
  453. #endif
  454.     (void) dohttptdisc (0, argv, p);
  455.     (void) dohttpcookies (0, argv, p);
  456.     tputc ('\n');
  457.     return 0;
  458. }
  459.  
  460.  
  461.  
  462. static int
  463. dohttpexeccmd (int argc, char *argv[], void *p OPTIONAL)
  464. {
  465.     return setbool (&HTTPexeccmd, "Enable Server-side include 'exec cmd's", argc, argv);
  466. }
  467.  
  468.  
  469.  
  470. static int
  471. dohttpstatusurl (int argc, char *argv[], void *p OPTIONAL)
  472. {
  473.     return setbool (&HTTPstatusURL, "Enable status URL (/status)", argc, argv);
  474. }
  475.  
  476.  
  477.  
  478. #ifdef HTTPCGI
  479. static int
  480. dohttpexeccgi (int argc, char *argv[], void *p OPTIONAL)
  481. {
  482.     return setbool (&HTTPexeccgi, "Enable Server-side include 'exec cgi's", argc, argv);
  483. }
  484. #endif
  485.  
  486.  
  487.  
  488. #ifdef STRICT_HTTPCALL
  489. static int
  490. dohttpstrict (int argc, char *argv[], void *p OPTIONAL)
  491. {
  492.     return setbool (&HTTPstrict, "Allow HTTP access from callsigns, only: ", argc, argv);
  493. }
  494. #endif
  495.  
  496.  
  497.  
  498. #ifdef HTTPPBBS
  499. static int
  500. dohttpexecbbs (int argc, char *argv[], void *p OPTIONAL)
  501. {
  502.     return setbool (&HTTPexecbbs, "Enable Server-side include 'exec bbs's", argc, argv);
  503. }
  504.  
  505.  
  506.  
  507. static int
  508. dohttpanonsend (int argc, char *argv[], void *p OPTIONAL)
  509. {
  510.     /* related to the NO_HTTP_MAIL permission */
  511.     return setbool (&HTTPanonsend, "Allow anonymous users to SEND mail", argc, argv);
  512. }
  513. #endif
  514.  
  515.  
  516.  
  517. #if 0
  518. static int
  519. dohttpscript (int argc, char *argv[], void *p OPTIONAL)
  520. {
  521.     return setbool (&HTTPscript, "Enable Server-side include 'tscript's", argc, argv);
  522. }
  523. #endif
  524.  
  525.  
  526.  
  527. static int
  528. dohttpsecure (int argc, char *argv[], void *p OPTIONAL)
  529. {
  530. struct secureURL *sec;
  531. int didheader = 0;
  532.  
  533.     if (argc == 1)    {
  534.         /* display currently defined secured URL's */
  535.         for (sec = securedURLS; sec != NULLSECUREURL; sec = sec->next)    {
  536.             if (!didheader)    {
  537.                 didheader = 1;
  538.                 tprintf ("\nSecured URLs:\n");
  539.             }
  540.             tprintf ("/%s (%s): %s\n", sec->url, sec->realm, sec->pwfile);
  541.         }
  542.         if (didheader)
  543.             tputc ('\n');
  544.         return 0;
  545.     }
  546.  
  547.     if (argc != 4)    {
  548.         tputs ("usage: http secure <url_or_dir> <realmstring> <pwdfile>\n");
  549.         return 1;
  550.     }
  551.  
  552.     if (argv[1][0] != '/')    {
  553.         tputs ("The url MUST begin with a '/'\n");
  554.         return 1;
  555.     }
  556.  
  557.     if (argv[3][0] != '/')    {
  558.         tputs ("The pwdfile MUST be a complete pathname, starting with a '/'\n");
  559.         return 1;
  560.     }
  561.  
  562.     sec = (struct secureURL *) callocw (1, sizeof (struct secureURL));
  563.     sec->next = securedURLS;
  564.     securedURLS = sec;
  565.     sec->realm = strdup (argv[2]);
  566.     sec->pwfile = strdup (argv[3]);
  567.     sec->url = strdup (&argv[1][1]);
  568.     return 0;
  569. }
  570.  
  571.  
  572.  
  573. static int
  574. dohttpreferer (int argc, char *argv[], void *p OPTIONAL)
  575. {
  576.     return setbool (&HTTPreferer, "Log Referer Headers", argc, argv);
  577. }
  578.  
  579.  
  580.  
  581. static int
  582. dohttpcookielog (int argc, char *argv[], void *p OPTIONAL)
  583. {
  584.     return setbool (&HTTPcookie, "Log Incoming Cookie Headers", argc, argv);
  585. }
  586.  
  587.  
  588.  
  589. static int
  590. dohttpcookies (int argc, char *argv[], void *p OPTIONAL)
  591. {
  592.     return setbool (&HTTPusecookies, "Assign Cookies", argc, argv);
  593. }
  594.  
  595.  
  596.  
  597. static int
  598. dohttpagent (int argc, char *argv[], void *p OPTIONAL)
  599. {
  600.     return setbool (&HTTPagent, "Log User-Agent Headers", argc, argv);
  601. }
  602.  
  603.  
  604.  
  605. static int
  606. dohttpmisc (int argc, char *argv[], void *p OPTIONAL)
  607. {
  608.     return setbool (&HTTPmisc, "Log Misc Headers", argc, argv);
  609. }
  610.  
  611.  
  612.  
  613. static int
  614. dohttppost (int argc, char *argv[], void *p OPTIONAL)
  615. {
  616.     return setbool (&HTTPpost, "Log POST Requests", argc, argv);
  617. }
  618.  
  619.  
  620.  
  621. static int
  622. dohttpmax (int argc, char *argv[], void *p OPTIONAL)
  623. {
  624.     return setint (&Httpmax, "Max. HTTP connects", argc, argv);
  625. }
  626.  
  627.  
  628.  
  629. static int
  630. dohttpsim (int argc, char *argv[], void *p OPTIONAL)
  631. {
  632.     return setint (&Httpsimc, "Simult. HTTP conn.'s serviced", argc, argv);
  633. }
  634.  
  635.  
  636.  
  637. static int
  638. dohttptdisc (int argc, char *argv[], void *p OPTIONAL)
  639. {
  640.     return setint (&Httptdisc, "HTTP Server tdisc (sec)", argc, argv);
  641. }
  642.  
  643.  
  644.  
  645. static int
  646. dohttphostname (int argc, char *argv[], void *p OPTIONAL)
  647. {
  648.     if (argc < 2)    {
  649.         if (HTTPHostname == NULLCHAR && Hostname)
  650.             HTTPHostname = strdup (Hostname);
  651.         if (HTTPHostname)
  652.             tprintf ("Default HTTP Hostname: %s\n", HTTPHostname);
  653.         return 0;
  654.     }
  655.     if (HTTPHostname)
  656.         free (HTTPHostname);
  657.     HTTPHostname = strdup (argv[1]);
  658.     return 0;
  659. }
  660.  
  661.  
  662.  
  663. static int
  664. dohttpftpdir (int argc, char *argv[], void *p OPTIONAL)
  665. {
  666.     if (argc < 2)    {
  667.         tprintf ("Default HTTP FTP directory: %s\n", (HTTPFtpdir) ? HTTPFtpdir : "none - disabled");
  668.         return 0;
  669.     }
  670.     if (HTTPFtpdir)
  671.         free (HTTPFtpdir);
  672.     HTTPFtpdir = strdup (argv[1]);
  673.     return 0;
  674. }
  675.  
  676.  
  677.  
  678. /* Start up http service */
  679. int
  680. httpstart (int argc, char *argv[], void *p OPTIONAL)
  681. {
  682. int port, k;
  683. uint32 address = INADDR_ANY;
  684.  
  685.     if (HTTPHostname == NULLCHAR)     {
  686.         if (Hostname)
  687.             HTTPHostname = strdup (Hostname);
  688.         else
  689.             HTTPHostname = strdup ("localhost");
  690.     }
  691.  
  692.     if(argc < 2 || argv[1][0] == '-')
  693.         port = IPPORT_HTTP;
  694.     else    {
  695.         if (argv[1][0] == '?')    {
  696.             /* they don't really want to start it, they want usage info */
  697.             tprintf ("usage: start http [<port> [<rootdir> [<hostname> [<ipaddress>] [ftpdir]]]]\n");
  698.             return 0;
  699.         }
  700.         port = atoi(argv[1]);
  701.     }
  702.  
  703.     if (argc > 4 && argv[4][0] != '-')    {
  704.         address = resolve (argv[4]);
  705.         if (address == 0L)    {
  706.             tprintf ("IP address %s does NOT resolve! HTTP server NOT started on port %d!\n",
  707.                 argv[4], port);
  708.             return 0;
  709.         }
  710.     }
  711.  
  712.     for (k = 0; k < MAXHTTPPORTS; k++) {
  713.         if (ports[k].port == port && ports[k].address == address)    {
  714.             tprintf ("Sorry, but you already have an HTTP server on port #%d for that address!\n", port);
  715.             return 0;
  716.         }
  717.     }
  718.  
  719.     for (k = 0; k < MAXHTTPPORTS; k++) {
  720.         if (ports[k].sock <= 0)
  721.             break;
  722.     }
  723.     if (k == MAXHTTPPORTS)    {
  724.         tprintf ("Sorry, but all %d HTTP ports are assigned!\n", MAXHTTPPORTS);
  725.         return 0;
  726.     }
  727.  
  728.     if(argc < 3 || argv[2][0] == '-')
  729.         ports[k].dirname = strdup (HTTPdir);
  730.     else
  731.         ports[k].dirname = strdup (argv[2]);
  732.  
  733.     if (argc < 4 || argv[3][0] == '-')
  734.         ports[k].hostname = strdup (HTTPHostname);
  735.     else
  736.         ports[k].hostname = strdup (argv[3]);
  737.  
  738.     if (argc < 5 || argv[4][0] == '-')
  739.         ports[k].ftpdirname = (HTTPFtpdir) ? strdup (HTTPFtpdir) : NULLCHAR;
  740.     else
  741.         ports[k].ftpdirname = strdup (argv[4]);
  742.  
  743.     ports[k].sock = -1;
  744.     ports[k].port = port;
  745.     ports[k].address = address;
  746.  
  747.     return (installserver (argc, argv, &ports[k].sock, "HTTP Listener", ports[k].port,
  748.         ports[k].address, "HTTP Server", httpserv, 1024, (void *)k));
  749. }
  750.  
  751.  
  752.  
  753. int
  754. http0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  755. {
  756. int port, k;
  757.  
  758.     if(argc < 2)
  759.         port = IPPORT_HTTP;
  760.     else
  761.         port = atoi(argv[1]);
  762.     for (k = 0; k < MAXHTTPPORTS; k++) {
  763.         if (ports[k].port == port)    {
  764.             ports[k].port = 0;
  765.             free (ports[k].dirname);
  766.             ports[k].dirname = NULLCHAR;
  767.             free (ports[k].hostname);
  768.             ports[k].hostname = NULLCHAR;
  769.             return (deleteserver (&ports[k].sock));
  770.         }
  771.     }
  772.     tprintf ("Sorry, but no HTTP server was found on port #%d!\n", port);
  773.     return 0;
  774. }
  775.  
  776.  
  777.  
  778. /* Creates a copy of string which has '%' escaped charecters decoded
  779.    back to ASCII. Allocates memory. Caller must free it. */
  780.  
  781.  
  782. static char *
  783. decode (char *string)
  784. {
  785. int i,k,slen;
  786. char code[3],*tmp;
  787.  
  788.     slen = (int) strlen (string);
  789.     tmp = mallocw ((unsigned int) (slen + 1));
  790.     i = k = 0;
  791.  
  792.     while (i <= slen) {
  793.         if (string[i] == '%') {
  794.             string[i] = '#';        /* '%' sign causes problems in log()  */
  795.             code[0] = string[i+1];
  796.             code[1] = string[i+2];
  797.             code[2] = '\0';
  798.             tmp[k] = (char)htoi(code);
  799.             k++;  i += 3;
  800.         } else
  801.             tmp[k++] = string[i++];
  802.     }
  803.     return tmp;
  804. }
  805.  
  806.  
  807.  
  808. #ifdef HTTPPBBS
  809. static void
  810. doPBBScmd (struct reqInfo *rq, const char *cmdstr)
  811. {
  812.     doPBBScmd_init (rq);
  813.     strncpy (rq->m->line, cmdstr, MBXLINE);
  814.     doPBBScmd_term (rq);
  815. }
  816.  
  817.  
  818.  
  819. static void
  820. doPBBScmd_init (struct reqInfo *rq)
  821. {
  822.     rq->m = newmbx (1);
  823.     rq->m->privs = rq->privs;
  824.     rq->m->sid = MBX_HTTP;
  825.     rq->m->user = Curproc->output;
  826.     rq->m->path = rq->bbspath;
  827.     if (!rq->username)
  828.         rq->username = strdup ("anonymous");
  829.     strncpy (rq->m->name, rq->username, 19);
  830.     if (rq->areaname)
  831.         changearea (rq->m, rq->areaname, 0);
  832. }
  833.  
  834.  
  835.  
  836. static void
  837. doPBBScmd_term (struct reqInfo *rq)
  838. {
  839.     if (rq->m)    {
  840.         (void) mbx_parse (rq->m);
  841.         doPBBScmd_exit (rq);
  842.     }
  843. }
  844.  
  845.  
  846.  
  847. static void
  848. doPBBScmd_exit (struct reqInfo *rq)
  849. {
  850.     if (rq->m)    {
  851.         rq->m->path = NULLCHAR;
  852.         setlastread (rq->m);
  853.         exitbbs(rq->m);
  854.         rq->m = NULLMBX;
  855.     }
  856. }
  857.  
  858.  
  859.  
  860. static void
  861. addUserFile (struct reqInfo *rq)
  862. {
  863. char fname[256];
  864.  
  865.     sprintf (fname, "%s/bbs/user.%s", rq->dirname, HTMLEXT);
  866.     addMsgFile (fname, rq);
  867. }
  868.  
  869.  
  870.  
  871. static void
  872. addMsgFile (char *fname, struct reqInfo *rq)
  873. {
  874. FILE *fp;
  875.  
  876.     if ((fp = fopen (fname, READ_BINARY)) != NULLFILE) {
  877.         sendhtml (fp, 1, rq);
  878.         (void) fclose (fp);
  879.     }
  880. }
  881.  
  882.  
  883.  
  884. static int
  885. checkareaperms (struct reqInfo *rq)
  886. {
  887. int retval = 0;
  888.  
  889.     /* only return a 1 if (1) it's our area, (2) we are a sysop, or
  890.        (3) it is a public area. Else, return a zero
  891.      */
  892.  
  893.     if (!stricmp(rq->areaname, rq->username) || (rq->privs & SYSOP_CMD) || isarea(rq->areaname))
  894.         retval = 1;
  895.     return retval;
  896. }
  897.  
  898. #endif
  899.  
  900.  
  901.  
  902. static int
  903. addFile (const char *fname, int s)
  904. {
  905. FILE *fp;
  906.  
  907.     if ((fp = fopen (fname, READ_BINARY)) != NULLFILE) {
  908.         (void) sendfile (fp, s, IMAGE_TYPE, 0);
  909.         (void) fclose (fp);
  910.         return 1;
  911.     }
  912.     return 0;
  913. }
  914.  
  915.  
  916.  
  917. static void
  918. httpserv (int s, void *v1, void *p OPTIONAL)
  919. {
  920. char command[PLINELEN], *cp, *newcommand, *tmp, *version;
  921. FILE *fp = NULLFILE;
  922. int port, length, i, err = 1, head = 0, retval = 200;
  923. struct stat sb;
  924. int isdir = 0;
  925. struct reqInfo *rq;
  926. char poststr[PLINELEN + 16];
  927. int posted_message = 0;
  928. struct sockaddr fsocket;
  929. uint32 addr;
  930. register struct usock *up;
  931. int isValidFtpRequest = 0;
  932. time_t nowtime;
  933.  
  934.     (void) sockowner (s, Curproc);
  935.     (void) sockmode (s, SOCK_ASCII);
  936.  
  937.     chname (Curproc, "HTTP Server - Init");
  938.     rq = (struct reqInfo *)callocw (1, sizeof (struct reqInfo));
  939.     if (rq == (struct reqInfo *)0)
  940.         return;
  941.         
  942.     rq->sizefmt = SIZEFMT_KMG;
  943.     rq->useerror = strdup (DEFAULT_ERROR_MSG);
  944.     rq->usetime = strdup (DEFAULT_TIME_FORMAT);
  945.     rq->index = (int) v1;
  946.     rq->port = ports[rq->index].port;
  947.     rq->hostname = ports[rq->index].hostname;
  948.     ports[rq->index].requests++;
  949. #ifdef STATS_HTTP
  950.     STATS_addhttp (0);
  951. #endif
  952.  
  953.     if (getpeername (s, (char *) &fsocket, &i) != -1)    {
  954.         port = DTranslate;
  955.         DTranslate = 0;
  956.         rq->rmtaddr = strdup (psocket (&fsocket));
  957.         if ((cp = strchr (rq->rmtaddr, ':')) != NULLCHAR)
  958.             *cp = 0;
  959.         addr = aton (rq->rmtaddr);
  960.         DTranslate = 1;
  961.         rq->rmthost = strdup (inet_ntoa (addr));
  962.         DTranslate = port;
  963.     } else    {
  964.         rq->rmthost = strdup ("unknown");
  965.         rq->rmtaddr = strdup ("unknown");
  966.     }
  967.  
  968.     close_s(Curproc->output);
  969.     close_s(Curproc->input);
  970.     Curproc->output = Curproc->input = s;
  971.     rq->sock = s;
  972.  
  973.     /* see if we have too many connections */
  974.     if (Httpmax <= HttpUsers)    {
  975.         tprintf("HTTP/1.0 503 Service Unavailable\n%s %s%s\n\n<TITLE>Busy</TITLE><H1>Busy</H1>\nTry again later.\n",HTTPHdrs[0],CTypes1[HTTPtypes[HTTPhtml].type1],HTTPtypes[HTTPhtml].type2);
  976.         HttpUsers++;
  977.         goto quit;
  978.     }
  979.  
  980.     HttpUsers++;
  981. #ifdef STATS_USE
  982.     STATS_adduse (1);
  983. #endif
  984.     sprintf (command, "HTTP Server - Waiting (%s)", rq->rmthost);
  985.     chname (Curproc, command);
  986.  
  987.     /* only allow Httpsimc connections to be active at a time */
  988.     while (HttpSessions >= Httpsimc)    {
  989.         kalarm (5000L);
  990.         kwait(&HttpSessions);
  991.         kalarm (0L);
  992.         if((up = itop(s)) == NULLUSOCK || up->cb.p == NULLCHAR)
  993.             break;
  994.     }
  995.     HttpSessions++;
  996.  
  997.     kalarm (Httptdisc * 1000L);
  998.     if (recvline (s, (unsigned char *) command, PLINELEN) == -1)
  999.         goto quit;
  1000.     kalarm (0L);
  1001.  
  1002.     sprintf (poststr, "HTTP Server - Processing (%s)", rq->rmthost);
  1003.     chname (Curproc, poststr);
  1004.  
  1005.     port = ports[(int)v1].port;
  1006.     rq->dirname = ports[rq->index].dirname;
  1007.     if (ports[rq->index].ftpdirname == NULLCHAR && HTTPFtpdir)
  1008.         /* newly defined default - allow it to set after the fact */
  1009.         ports[rq->index].ftpdirname = strdup (HTTPFtpdir);
  1010.     rq->ftpdirname = ports[rq->index].ftpdirname;
  1011.     
  1012.     rip (command);
  1013.     if (!*command)    {
  1014.         retval = 400;
  1015.         usputs (s, "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n<BODY><H1>400 Bad Request</H1>\nYour client sent a query that this server could not understand.<P>\nReason: Invalid HTTP/0.9 method.<P></BODY>\n");
  1016.         goto quit;
  1017.     }
  1018.  
  1019.     tmp = decode (command);
  1020.     cp = strchr (tmp, ' ');
  1021.     if (cp == NULLCHAR)    {
  1022.         retval = 400;
  1023.         usputs (s, "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n<BODY><H1>400 Bad Request</H1>\nYour client sent a query that this server could not understand.<P>\nReason: No URL given.<P></BODY>\n");
  1024.         goto quit;
  1025.     }
  1026.     *cp++ = 0;
  1027.     newcommand = ++cp;
  1028.     version = strchr (newcommand, ' ');
  1029.     if (version != NULLCHAR)
  1030.         *version++ = 0;
  1031.     
  1032.     /* at this point, tmp=command, newcommand=ulr, and version=httpversion info */
  1033.     if (!strcmp (newcommand, "/"))
  1034.         newcommand++;
  1035.     if (!*newcommand)
  1036.         ports[rq->index].homehits++;
  1037.     
  1038.     rq->url = strdup (newcommand);
  1039.     rq->version = strdup (version);
  1040.     rq->method = strdup (tmp);
  1041.     length = (int) strlen (newcommand);
  1042.  
  1043.     /* if HTTP 0.9 (no version string), only 'GET' is allowed */
  1044.     if (version == NULLCHAR && strncmp (command, "GET", 3))    {
  1045.         retval = 400;
  1046.           httpHeaders (HTTPhtml, "400 Bad Request", rq, 0, NULLCHAR);
  1047.         usputs (s, "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n<BODY><H1>400 Bad Request</H1>\nYour client sent a query that this server could not understand.<P>\nReason: Invalid HTTP/0.9 method.<P></BODY>\n");
  1048.         goto quit0;
  1049.     }
  1050.  
  1051.     /* not complete yet, but it at least logs it and responds ;-) */
  1052.     poststr[0] = 0;
  1053.     if (!strncmp (command, "POST", 4)){
  1054.         int postsize = 0;
  1055.         int headersdone = 0;
  1056.  
  1057.         /* if posting PBBS email, open a file for the post contents */
  1058.         if (!strcmp (newcommand, "bbs/sendmail"))
  1059.             posted_message = 1;
  1060.  
  1061.         if (HTTPpost != 0)    {
  1062.             openHTTPlog("post");
  1063.             simple_log (s, command);
  1064.             closeHTTPlog();
  1065.         }
  1066.         while (kalarm (Httptdisc * 1000L),recvline (s, (unsigned char *) rq->buf, sizeof(rq->buf)) != -1) {
  1067.             kalarm (0L);
  1068.             if (headersdone)
  1069.                 postsize -= (int) strlen(rq->buf);
  1070.             rip (rq->buf);
  1071.             if (HTTPpost != 0)    {
  1072.                 openHTTPlog("post");
  1073.                 simple_log (s, rq->buf);
  1074.                 closeHTTPlog();
  1075.             }
  1076.  
  1077.             /* if this is an incoming email posting, check for auth string */
  1078.             if (posted_message)    {
  1079.                 /* look for cookie header line */
  1080.                 if (!strnicmp (rq->buf, HTTPHdrs[HDR_COOKIE], strlen(HTTPHdrs[HDR_COOKIE])))
  1081.                     rq->cookie = strdup (&rq->buf[strlen(HTTPHdrs[HDR_COOKIE]) + 1]);
  1082.                 /* also look for auth header line */
  1083.                 if (!strnicmp (rq->buf, HTTPHdrs[HDR_AUTHORIZE], strlen(HTTPHdrs[HDR_AUTHORIZE])))
  1084.                     rq->passwd = strdup (&rq->buf[strlen(HTTPHdrs[HDR_AUTHORIZE]) + 7]);
  1085.             }
  1086.  
  1087.             if (!strnicmp (rq->buf, HTTPHdrs[1], strlen(HTTPHdrs[1])))    {
  1088.                 postsize = atoi(&rq->buf[strlen(HTTPHdrs[1])]);
  1089.                 continue;
  1090.             } else if (!*rq->buf && !headersdone)    {
  1091.                 headersdone = 1;
  1092.                 if (!postsize)    {
  1093.                     retval = 400;
  1094.                     httpHeaders (HTTPhtml, "400 Bad Request", rq, 0, NULLCHAR);
  1095.                     usputs (s, "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n<BODY><H1>400 Bad Request</H1>\nYour client sent an improperly formatted POST - no size given.</BODY>\n");
  1096.                     goto quit0;
  1097.                 }
  1098.                 /* one more line with content */
  1099.                 continue;
  1100.             }
  1101.  
  1102.             if (!headersdone)
  1103.                 continue;
  1104.                 
  1105.             if (!posted_message)    {
  1106. #if 1
  1107.                 if (postsize <= 0)
  1108.                     break;
  1109. #endif
  1110.                 continue;
  1111.             }
  1112.  
  1113.             /* if this is a posted message, this will be our data line - save it */
  1114.             strncpy (poststr, rq->buf, PLINELEN + 16);
  1115.             break;
  1116.         }
  1117.         kalarm (0L);
  1118.  
  1119.         if (posted_message)
  1120.             goto http_bbs_entry;
  1121.  
  1122.         /* if this is NOT an email posting, return an okay and bitbucket the posting action */
  1123. post_response:
  1124.         retval = 202;
  1125.         httpHeaders (HTTPhtml, "202 Accepted", rq, 0, NULLCHAR);
  1126.         usputs (s, "<HEAD><TITLE>202 Post Accepted</TITLE></HEAD>\n<BODY><H1>202 Post Accepted</H1>\nThe TNOS server has accepted and logged your posting.</BODY>\n");
  1127.         goto quit0;
  1128.     }
  1129.  
  1130.     if (!strncmp (command, "HEAD", 4))
  1131.         head = 1;
  1132.  
  1133.     if (version != NULLCHAR && !strnicmp (version, "HTTP/", 5)) {
  1134.         /* we must wait to receive header lines, until a blank line */
  1135.         while (kalarm (Httptdisc * 1000L), recvline (s, (unsigned char *) rq->buf, sizeof(rq->buf)) != -1) {
  1136.             kalarm (0L);
  1137.             rip (rq->buf);
  1138.             if (!*rq->buf)
  1139.                 break;
  1140.             if (!strnicmp (rq->buf, HTTPHdrs[HDR_COOKIE], strlen(HTTPHdrs[HDR_COOKIE])))    {
  1141.                 rq->cookie = strdup (&rq->buf[strlen(HTTPHdrs[HDR_COOKIE]) + 1]);
  1142.                 if (HTTPcookie == 0)
  1143.                     continue;
  1144.                 openHTTPlog("cookies");
  1145.                 sprintf (rq->buf, "%s; URL=%s", rq->cookie, rq->url);
  1146.             } else if (!strnicmp (rq->buf, HTTPHdrs[HDR_LENGTH], strlen(HTTPHdrs[HDR_LENGTH]))) {
  1147.                 rq->qsize = atoi (&rq->buf[strlen(HTTPHdrs[HDR_LENGTH]) + 1]);
  1148.                 if (HTTPmisc == 0)
  1149.                     continue;
  1150.                 openHTTPlog("mischttp");
  1151.             } else if (!strnicmp (rq->buf, HTTPHdrs[HDR_SINCE], strlen(HTTPHdrs[HDR_SINCE]))) {
  1152.                 rq->newcheck = strdup (&rq->buf[strlen(HTTPHdrs[HDR_SINCE]) + 1]);
  1153.                 if (HTTPmisc == 0)
  1154.                     continue;
  1155.                 openHTTPlog("mischttp");
  1156.             } else if (!strnicmp (rq->buf, HTTPHdrs[HDR_FROM], strlen(HTTPHdrs[HDR_FROM]))) {
  1157.                 rq->from = strdup (&rq->buf[strlen(HTTPHdrs[HDR_FROM]) + 1]);
  1158.                 if (HTTPmisc == 0)
  1159.                     continue;
  1160.                 openHTTPlog("mischttp");
  1161.             } else if (!strnicmp (rq->buf, HTTPHdrs[HDR_AUTHORIZE], strlen(HTTPHdrs[HDR_AUTHORIZE]))) {
  1162.                 rq->passwd = strdup (&rq->buf[strlen(HTTPHdrs[HDR_AUTHORIZE]) + 7]);
  1163.                 if (HTTPmisc == 0)
  1164.                     continue;
  1165.                 openHTTPlog("mischttp");
  1166.             } else if (!strnicmp (rq->buf, HTTPHdrs[HDR_REFERER], strlen(HTTPHdrs[HDR_REFERER]))) {
  1167.                 rq->referer = strdup(&rq->buf[strlen(HTTPHdrs[HDR_REFERER]) + 1]);
  1168.                 if (HTTPreferer == 0)
  1169.                     continue;
  1170.                 openHTTPlog("referer");
  1171.                 sprintf (rq->buf, "%s -> /%s", rq->referer, rq->url);
  1172.             } else if (!strnicmp (rq->buf, HTTPHdrs[HDR_AGENT], strlen(HTTPHdrs[HDR_AGENT])))    {
  1173.                 rq->agent = strdup(&rq->buf[strlen(HTTPHdrs[HDR_AGENT]) + 1]);
  1174.                 if (HTTPagent == 0)
  1175.                     continue;
  1176.                 openHTTPlog("agent");
  1177.                 sprintf (rq->buf, "%s -> /%s", rq->agent, rq->url);
  1178.             } else    {
  1179.                 if (HTTPmisc == 0)
  1180.                     continue;
  1181.                 openHTTPlog("mischttp");
  1182.             }
  1183.             simple_log (s, rq->buf);
  1184.             closeHTTPlog();
  1185.         }
  1186.         kalarm (0L);
  1187.     }
  1188.     
  1189.     if (!head && strncmp (command, "GET", 3))    {
  1190.         /* not GET, HEAD, or POST, so we don't support it.... */
  1191.         retval = 400;
  1192.           httpHeaders (HTTPhtml, "400 Bad Request", rq, 0, NULLCHAR);
  1193.         usputs (s, "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n<BODY><H1>400 Bad Request</H1>\nYour client sent a query that this server could not understand.<P>\nReason: Invalid or unsupported method.<P></BODY>\n");
  1194.         goto quit0;
  1195.     }
  1196.  
  1197.     if (HTTPstatusURL && (!strcmp (newcommand, "status") || !strcmp (newcommand, "status/")))    {
  1198.         ports[rq->index].stathits++;
  1199.         rq->isvolatile = 1;
  1200.           httpHeaders (HTTPhtml, "200 Document follows", rq, 0, NULLCHAR);
  1201.         usprintf (s, "<HEAD><TITLE>Server Status at %s</TITLE></HEAD>\n", ports[rq->index].hostname);
  1202.         usputs (s, "<HTML><BODY><A HREF=\"http://www.lantz.com/tnos/\"><IMG SRC=\"http://www.lantz.com/tnos/tnos.gif\" align=left></A>");
  1203.         usprintf (s, "<H1>%s:%d</H1>\n<H2>Server Info</H2>\n", ports[rq->index].hostname, ports[rq->index].port);
  1204.  
  1205.         cp = ctime (&StartTime);
  1206.         rip (cp);
  1207.         usprintf (s, "<TABLE border=0><tr><td>Start Time</td><td>%s</td></tr>\n", cp);
  1208.         nowtime = time (&nowtime);
  1209.         cp = ctime (&nowtime);
  1210.         rip (cp);
  1211.         usprintf (s, "<tr><td>Current Time  </td><td>%s</td></tr>\n", cp);
  1212.  
  1213.         usputs (s, "<tr><td>Server</td><td>TNOS/"VERSION" "OS"</td></tr></table><pre>\n\n\n</pre><H3>Current Counters</H3>\n");
  1214.         usprintf (s, "<table border><tr><td>URL Requests</td><td> %ld </td></tr>\n", ports[rq->index].requests);
  1215.         usprintf (s, "<tr><td>Home Page Hits</td><td> %ld </td></tr>\n", ports[rq->index].homehits);
  1216.         usprintf (s, "<tr><td>Status Page Hits </td><td> %ld </td></tr>\n", ports[rq->index].stathits);
  1217. #ifdef HTTPPBBS
  1218.         usprintf (s, "<tr><td>PBBS Hits</td><td> %ld </td></tr>\n", ports[rq->index].bbshits);
  1219. #endif
  1220.         usprintf (s, "<tr><td>Active Requests</td><td> %d </td></tr>\n</table>\n", HttpUsers);
  1221.  
  1222. #ifdef STATS_HTTP
  1223.         usputs (s, "<pre>\n\n\n</pre><HR><H3>General Statistics</H3><PRE>\n");
  1224.         doPBBScmd (rq, "stats h g");
  1225.  
  1226.         usputs (s, "<pre>\n\n\n</pre><HR><H3>Daily Statistics</H3><PRE>\n");
  1227.         doPBBScmd (rq, "stats h d");
  1228.  
  1229.         usputs (s, "<pre>\n\n\n</pre><HR><H3>Weekly Statistics</H3><PRE>\n");
  1230.         doPBBScmd (rq, "stats h w");
  1231.  
  1232.         usputs (s, "<pre>\n\n\n</pre><HR><H3>Monthly Statistics</H3><PRE>\n");
  1233.         doPBBScmd (rq, "stats h m");
  1234.  
  1235.         usputs (s, "<pre>\n\n\n</pre><HR><H3>Yearly Statistics</H3><PRE>\n");
  1236.         doPBBScmd (rq, "stats h y");
  1237. #endif
  1238.  
  1239.         usputs (s, "<pre>\n\n\n</pre><HR><H5>For further information on TNOS can be found at <A HREF=\"http://www.lantz.com/tnos\">TNOS Central</A></H5>\n</HTML>\n");
  1240.         goto quit0;
  1241.     }
  1242. #ifdef HTTPPBBS
  1243. http_bbs_entry:
  1244.     if (!strncmp (newcommand, "bbs", 3))    {
  1245.         ports[rq->index].bbshits++;
  1246. #ifdef STATS_HTTP
  1247.         STATS_addhttp (1);
  1248. #endif
  1249.         /* if no authentication, it fails */
  1250.         if (rq->passwd == NULLCHAR)    {
  1251.             goto failauthorize;
  1252.         } else {
  1253.             /* check the authentication, here */
  1254.             char *tmp64, *cp2, pathbuf[MBXLINE], *path = pathbuf;
  1255.             if ((tmp64 = base64ToStr(rq->passwd)) == NULLCHAR)
  1256.                 goto failauthorize;
  1257. #if 0
  1258.             log (-1, "HTTP Authentication Test: '%s' - '%s'", rq->passwd, (tmp64) ? tmp64 : "unknown");
  1259. #endif
  1260.             if (tmp64[0] == ':' || (cp2 = strchr (tmp64, ':')) == NULLCHAR)
  1261.                 goto failauthorize0;
  1262.  
  1263.             *cp2++ = 0;
  1264.             if((rq->privs = userlogin(tmp64,cp2,&path,MBXLINE,&rq->anony)) == -1 || (rq->privs & NO_HTTP_IP) || (rq->privs & EXCLUDED_CMD))    {
  1265.                 /* invalid authentication */
  1266. failauthorize0:            free (tmp64);
  1267. failauthorize:            retval = 401;
  1268.                 httpHeaders (HTTPhtml, "401 Unauthorized", rq, 0, "the TNOS PBBS");
  1269.                 usputs (s, "<HEAD><TITLE>Authorization Failed</TITLE></HEAD>\n<BODY><H1>Authorization Failed</H1>\nThe TNOS server requires proper authorization for this URL. Either your browser does not perform authorization, or your authorization has failed.</BODY>\n");
  1270.                 goto quit0;
  1271.             }
  1272. #ifdef STRICT_HTTPCALL
  1273.             if (HTTPstrict && !(rq->privs & SYSOP_CMD) && !iscall(tmp64))
  1274.                 goto failauthorize0;
  1275. #endif
  1276.             if (rq->privs & WAS_ANONY)    {
  1277.                 int ii, trans;
  1278.                 char *cptr, *cptr2;
  1279.  
  1280.                 ii = SOCKSIZE;
  1281.                 trans = DTranslate; /* Save IP address translation state */
  1282.                 DTranslate = 0;     /* Force output to be numeric IP addr*/
  1283.                 if (getpeername(s,(char *)&fsocket,&ii) != -1)    {
  1284.                     cptr = psocket(&fsocket);
  1285.                     if ((cptr2 = strchr(cptr, ':')) != NULLCHAR)
  1286.                         *cptr2 = 0;
  1287.                     if (strcmp(inet_ntoa(NonSecureAmpr), cptr) && (!*cptr || !strnicmp (cptr, "44.", 3) || !strnicmp (cptr, "127.0.0.1", 9)))    {
  1288.                         if (MbAmprPerms)
  1289.                             rq->privs = MbAmprPerms;
  1290.                     } else if (MbNonAmprPerms)
  1291.                         rq->privs = MbNonAmprPerms;
  1292.                 } else if (MbNonAmprPerms)
  1293.                     rq->privs = MbNonAmprPerms;
  1294.                 DTranslate = trans;             /* Restore original state */
  1295.                 if (MbHttpPerms)
  1296.                     rq->privs = MbHttpPerms;
  1297.                 rq->privs |= WAS_ANONY;
  1298.             }
  1299.             rq->username = strdup (tmp64);
  1300.             (void) strlwr (rq->username);
  1301.             rq->bbspath = strdup (pathbuf);
  1302.             free (tmp64);
  1303.         }
  1304.         /* passed authentication - now check for special URLs */
  1305.         
  1306.         /* if URL is 'bbs' or 'bbs/', then change it to 'bbs/${username}.html' */
  1307.         if (strlen(newcommand) == 3 || !strcmp (newcommand, "bbs/"))    {
  1308.             retval = 302;
  1309.             sprintf (rq->buf, "bbs/%s.%s", rq->username, HTMLEXT);
  1310.             free (rq->url);
  1311.             rq->url = strdup (rq->buf);
  1312.               httpHeaders (HTTPhtml, "302 Found", rq, 0, NULLCHAR);
  1313.               if (!head)
  1314.                 usprintf (s, "<TITLE>Document moved</TITLE><H1>Document moved</H1>Please,"
  1315.                    "\n<A HREF=\"http://%s/%s\">click here</A>\n",
  1316.                    rq->hostname,rq->url);
  1317.             goto quit0;
  1318.         }
  1319.  
  1320.         /* if URL is 'bbs/area', then change it to 'bbs/area/${username}.html' */
  1321.         if (!strcmp (newcommand, "bbs/area"))    {
  1322.             retval = 302;
  1323.             sprintf (rq->buf, "bbs/area/%s.%s", rq->username, HTMLEXT);
  1324.             free (rq->url);
  1325.             rq->url = strdup (rq->buf);
  1326.               httpHeaders (HTTPhtml, "302 Found", rq, 0, NULLCHAR);
  1327.               if (!head)
  1328.                 usprintf (s, "<TITLE>Document moved</TITLE><H1>Document moved</H1>Please,"
  1329.                    "\n<A HREF=\"http://%s/%s\">click here</A>\n",
  1330.                    rq->hostname, rq->url);
  1331.             goto quit0;
  1332.         }
  1333.  
  1334.         /* if URL is 'bbs/message/areaname', then change it to 'bbs/area/areaname.html' */
  1335.         if (!strncmp (newcommand, "bbs/message/", 12) && !strstr (newcommand, ".htm"))    {
  1336.             cp = &newcommand[12];
  1337.             sprintf (rq->buf, "bbs/area/%s.%s", cp, HTMLEXT);
  1338.             free (rq->url);
  1339.             rq->url = strdup (rq->buf);
  1340.             retval = 302;
  1341.               httpHeaders (HTTPhtml, "302 Found", rq, 0, NULLCHAR);
  1342.               if (!head)
  1343.                 usprintf (s, "<TITLE>Document moved</TITLE><H1>Document moved</H1>Please,"
  1344.                    "\n<A HREF=\"http://%s/%s\">click here</A>\n",
  1345.                    rq->hostname, rq->url);
  1346.             goto quit0;
  1347.         }
  1348.  
  1349.         /* if URL is 'bbs/$(username}.html', then build it */
  1350.         sprintf (rq->buf, "bbs/%s.%s", rq->username, HTMLEXT);
  1351.         if (!strcmp (rq->buf, newcommand))    {
  1352.             /* special URL for user's login */
  1353.             rq->isvolatile = 1;
  1354.               httpHeaders (HTTPhtml, "200 Document follows", rq, 1, NULLCHAR);
  1355.               addUserFile (rq);
  1356.             goto quit0;
  1357.         }
  1358.  
  1359.         /* if URL is 'bbs/area/${areaname}.html', then build an area feature page */
  1360.         if (!strncmp (newcommand, "bbs/area/", 9) && !strchr(&newcommand[9], '/') && strstr (newcommand, ".htm"))    {
  1361.             char *cp2;
  1362.             /* special URL for area listing */
  1363.               strncpy (rq->buf, &newcommand[9], PLINELEN + 16);
  1364.               cp2 = strstr (rq->buf, ".htm");
  1365.               if (cp2)
  1366.                 *cp2 = 0;
  1367.               rq->areaname = strdup (rq->buf);
  1368.  
  1369.               if (!checkareaperms (rq))
  1370.                   goto failauthorize;
  1371.               
  1372.             doPBBScmd_init (rq);
  1373.             rq->msgcount = rq->m->nmsgs;
  1374.             rq->newmsgcount = rq->m->newmsgs;
  1375.             rq->msgcurrent = rq->m->current;
  1376.  
  1377.             rq->isvolatile = 1;
  1378.               httpHeaders (HTTPhtml, "200 Document follows", rq, 1, NULLCHAR);
  1379.             sprintf (rq->buf, "%s/bbs/areaopt.%s", rq->dirname, HTMLEXT);
  1380.               addMsgFile (rq->buf, rq);
  1381.             goto quit0;
  1382.         }
  1383.  
  1384.         /* if URL is 'bbs/area/areaname/xxx.html', then build an area list, starting w/msg#xxx */
  1385.         if (!strncmp (newcommand, "bbs/area/", 9))    {
  1386.             char *cp2, *cp3;
  1387.             /* special URL for area listing */
  1388.               strncpy (rq->buf, &newcommand[9], PLINELEN + 16);
  1389.               if ((cp2 = strchr (rq->buf, '/')) == NULLCHAR)
  1390.                   goto failauthorize;
  1391.               *cp2++ = 0;
  1392.               rq->areaname = strdup (rq->buf);
  1393.  
  1394.               if (!checkareaperms (rq))
  1395.                   goto failauthorize;
  1396.               
  1397.               if ((cp3 = strchr (cp2, '.')) == NULLCHAR)
  1398.                   goto failauthorize;
  1399.               *cp3 = 0;
  1400.  
  1401.               rq->msgnum = atoi(cp2);
  1402.               if (!rq->msgnum && !strcmp (cp2, "new"))
  1403.                   rq->msgnum = -1;
  1404.               
  1405.             doPBBScmd_init (rq);
  1406.             rq->msgcount = rq->m->nmsgs;
  1407.             rq->newmsgcount = rq->m->newmsgs;
  1408.             rq->msgcurrent = rq->m->current;
  1409.  
  1410.             rq->isvolatile = 1;
  1411.               httpHeaders (HTTPhtml, "200 Document follows", rq, 1, NULLCHAR);
  1412.  
  1413.             strcpy (rq->m->line, "L");
  1414.             if (rq->msgnum != -1)
  1415.                 sprintf (&rq->m->line[1], " %d %d", rq->msgnum, rq->msgnum + 99);
  1416.  
  1417.             sprintf (rq->buf, "%s/bbs/arealist.%s", rq->dirname, HTMLEXT);
  1418.               addMsgFile (rq->buf, rq);
  1419.             goto quit0;
  1420.         }
  1421.  
  1422.         /* if URL is 'bbs/message/areaname/xxx.html', then build an message page */
  1423.         if (!strncmp (newcommand, "bbs/message/", 12))    {
  1424.             char *cp2, *cp3;
  1425.             /* special URL for reading messages */
  1426.             strncpy (rq->buf, &newcommand[12], PLINELEN + 16);
  1427.               if ((cp2 = strchr (rq->buf, '/')) == NULLCHAR)
  1428.                   goto failauthorize;
  1429.               *cp2++ = 0;
  1430.               rq->areaname = strdup (rq->buf);
  1431.  
  1432.               if (!checkareaperms (rq))
  1433.                   goto failauthorize;
  1434.               
  1435.               if ((cp3 = strchr (cp2, '.')) == NULLCHAR)
  1436.                   goto failauthorize;
  1437.               *cp3 = 0;
  1438.             rq->msgnum = atoi (cp2);
  1439.  
  1440.             doPBBScmd_init (rq);
  1441.             rq->msgcount = rq->m->nmsgs;
  1442.             rq->newmsgcount = rq->m->newmsgs;
  1443.             rq->msgcurrent = rq->m->current;
  1444.  
  1445.             rq->isvolatile = 1;
  1446.               httpHeaders (HTTPhtml, "200 Document follows", rq, 1, NULLCHAR);
  1447.  
  1448.             sprintf (rq->m->line, "%d", rq->msgnum);
  1449.             sprintf (rq->buf, "%s/bbs/msglist.%s", rq->dirname, HTMLEXT);
  1450.               addMsgFile (rq->buf, rq);
  1451.             goto quit0;
  1452.         }
  1453.  
  1454.         /* if URL is 'bbs/cmd/xxxx', then build an text page from the BBS output of 'xxxx' */
  1455.         if (HTTPexecbbs && !strncmp (newcommand, "bbs/cmd/", 8))    {
  1456.             char *cp2, *cp3;
  1457.  
  1458.             cp2 = &newcommand[8];
  1459.             if (!strncmp (cp2, "area?", 5))    {
  1460.                 cp3 = strchr (&cp2[5], '/');
  1461.                 if (cp3 != NULLCHAR)    {
  1462.                     cp2 += 5;
  1463.                     *cp3++ = 0;
  1464.                     rq->areaname = strdup (cp2);
  1465.                     cp2 = cp3;
  1466.                 }
  1467.             }
  1468.             while ((cp3 = strchr (cp2, '?')) != NULLCHAR)
  1469.                   *cp3 = ' ';
  1470.  
  1471.             rq->isvolatile = 1;
  1472.               httpHeaders (HTTPplain, "200 Document follows", rq, 0, NULLCHAR);
  1473.  
  1474.             doPBBScmd (rq, cp2);
  1475.             goto quit0;
  1476.         }
  1477.  
  1478.         /* if URL is 'bbs/sendmail', then build an email message from the posting */
  1479.         if (!strcmp (rq->method, "POST") && posted_message && !strcmp (newcommand, "bbs/sendmail"))    {
  1480.             char *tmp2, *tmp3, *tmp4, msgtype = 'P', specialchar[3];
  1481.             char *subject = NULLCHAR;
  1482.             char fromaddr[128];
  1483.             char *toaddr = NULLCHAR;
  1484.             FILE *postfp;
  1485.             
  1486.             if (rq->privs & (NO_HTTP_MAIL | NO_SENDCMD))    {
  1487.                 retval = 403;
  1488.                 httpHeaders (HTTPhtml, "403 Forbidden", rq, 0, NULLCHAR);
  1489.                 usputs (s, "<HEAD><TITLE>403 Post Forbidden</TITLE></HEAD>\n<BODY><H1>403 Post Forbidden</H1>\nThe TNOS server has rejected your posting.<p>\nYou do not have permission to post to this site.\n");
  1490.                 sprintf (fromaddr, "%s/bbs/sendfail.%s", HTTPdir, HTMLEXT);
  1491.                 if ((postfp = fopen (fromaddr, "r")) != NULLFILE)    {
  1492.                     sendhtml (postfp, 1, rq);
  1493.                     (void) fclose (postfp);
  1494.                 } else
  1495.                     usputs (s, "</BODY>\n");
  1496.  
  1497.                 goto quit0;
  1498.             }
  1499.  
  1500.             postfp = tmpfile ();
  1501.             if (postfp == NULLFILE)
  1502.                 goto post_response;    /* shouldn't happen */
  1503.  
  1504.             while ((cp = strchr (poststr, '+')) != NULLCHAR)
  1505.                 *cp = ' ';
  1506.             
  1507.             for (cp = poststr; cp != NULLCHAR; cp = tmp4)    {
  1508.                 tmp4 = strchr (cp, '&');
  1509.                 if (tmp4)
  1510.                     *tmp4++ = 0;
  1511.                 if ((tmp2 = strchr (cp, '=')) == NULLCHAR)
  1512.                     continue;
  1513.                 *tmp2++ = 0;
  1514.                 if (!strcasecmp (cp, "address"))    {
  1515.                     toaddr = decode(tmp2);
  1516.                     continue;
  1517.                 } else if (!strcasecmp (cp, "subject"))    {
  1518.                     subject = decode(tmp2);
  1519.                     continue;
  1520.                 } else if (!strcasecmp (cp, "type"))    {
  1521.                     msgtype = *tmp2;
  1522.                     continue;
  1523.                 } else if (strncasecmp (cp, "line", 4))
  1524.                     continue;
  1525.  
  1526.                 /* This is a data line, add to the temp file */
  1527.                 while ((tmp3 = strchr (tmp2, '%')) != NULLCHAR)    {
  1528.                     *tmp3++ = 0;
  1529.                     fputs (tmp2, postfp);
  1530.                     specialchar[0] = *tmp3++;
  1531.                     specialchar[1] = *tmp3++;
  1532.                     specialchar[2] = 0;
  1533.                     fputc (htoi (specialchar), postfp);
  1534.                     tmp2 = tmp3;
  1535.                 }
  1536.                 if (*tmp2)
  1537.                     fputs (tmp2, postfp);
  1538.                 fputc ('\n', postfp);
  1539.                 
  1540.             }
  1541.             if (toaddr)    {
  1542.                 sprintf (fromaddr, "%s@%s", rq->username, rq->hostname);
  1543.                 retval = 202;
  1544.                 httpHeaders (HTTPhtml, "202 Accepted", rq, 0, NULLCHAR);
  1545.                 usputs (s, "<HEAD><TITLE>202 Post Accepted</TITLE></HEAD>\n<BODY><H1>202 Post Accepted</H1>\nThe TNOS server has accepted and logged your posting.</BODY>\n");
  1546.  
  1547.                 rewind (postfp);
  1548.                 (void) rdaemon (postfp, NULLCHAR, fromaddr, toaddr, (subject) ? subject : "(no subject)", msgtype, 0);
  1549.                 smtptick (NULL);
  1550.             } else {
  1551.                 retval = 400;
  1552.                   httpHeaders (HTTPhtml, "400 Bad Request", rq, 0, NULLCHAR);
  1553.                 usputs (s, "<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n<BODY><H1>400 Bad Request</H1>\nYour client sent a query that this server could not understand.<P>\nReason: No email address given.<P></BODY>\n");
  1554.             }
  1555.  
  1556.             (void) fclose (postfp);
  1557.             free (toaddr);
  1558.             free (subject);
  1559.             goto quit0;
  1560.         }
  1561.  
  1562.         /* otherwise, it must be a regular html file in the 'bbs' directory */
  1563.     }
  1564. #endif
  1565.  
  1566.     if (is_authorized (rq) == FALSE)    {
  1567.         /* this url is protected and proper authentication wasn't given */
  1568.         retval = 401;
  1569.         httpHeaders (HTTPhtml, "401 Unauthorized", rq, 0, rq->realm);
  1570.         usputs (s, "<HEAD><TITLE>Authorization Failed</TITLE></HEAD>\n<BODY><H1>Authorization Failed</H1>\nThe TNOS server requires proper authorization for this URL. Either your browser does not perform authorization, or your authorization has failed.</BODY>\n");
  1571.         goto quit0;
  1572.     }
  1573.  
  1574.     if (length == 0)
  1575.         sprintf(rq->buf,"%s/index.%s", rq->dirname, HTMLEXT);
  1576.     else    {
  1577.         if (rq->ftpdirname && !strncmp (newcommand, "ftp", 3))    {
  1578.             char *newercommand = newcommand;
  1579.             /* viewing/retrieving files from defined FTP directory */
  1580.             newercommand += 3;
  1581.             if (*newercommand && *newercommand == '/')
  1582.                 newercommand++;
  1583.             sprintf(rq->buf, "%s/%s", rq->ftpdirname, newercommand);
  1584.             isValidFtpRequest = 1;
  1585.         } else
  1586.             sprintf(rq->buf,"%s/%s", rq->dirname, newcommand);
  1587.     }
  1588.  
  1589.     /* delete any .. to avoid */
  1590.     /* anyone telnetting to http and cd'ing to a directory */
  1591.     /* other than within Httpdir */
  1592.  
  1593.     for ( i=0; i <= (int) strlen(rq->buf); i++ ) {
  1594.         if (rq->buf[i] == '.' && rq->buf[i+1] == '.') {
  1595.             rq->buf[i] = ' ';
  1596.             rq->buf[i+1] = ' ';
  1597.         }
  1598.     }
  1599.  
  1600.     if (stat (rq->buf, &sb) != -1)
  1601.         isdir = sb.st_mode & S_IFDIR;
  1602.     if (rq->buf[strlen(rq->buf)-1] == '/') {
  1603.         strcat (rq->buf, "welcome." HTMLEXT);
  1604.         if (isValidFtpRequest || !access (rq->buf, 0))    {
  1605.             retval = 200;
  1606.               httpHeaders (HTTPhtml, "200 Document follows", rq, 0, NULLCHAR);
  1607.               if (!head)
  1608.                 err = mkwelcome (rq->dirname, rq->buf, isValidFtpRequest, rq->ftpdirname);
  1609.             goto quit0;
  1610.         }
  1611.     } else if (isdir) {
  1612.         retval = 302;
  1613.         strncpy (rq->buf, newcommand, PLINELEN + 15);
  1614.         strcat (rq->buf, "/");
  1615.         free (rq->url);
  1616.         rq->url = strdup (rq->buf);
  1617.           httpHeaders (HTTPhtml, "302 Found", rq, 0, NULLCHAR);
  1618.           if (!head)
  1619.             tprintf ("<TITLE>Document moved</TITLE><H1>Document moved</H1>Please,"
  1620.                "\n<A HREF=\"http://%s/%s\">click here</A>\n",
  1621.                rq->hostname, rq->url);
  1622.         goto quit0;
  1623.     } else
  1624.         fp = fopen (rq->buf, READ_BINARY);
  1625.  
  1626.     if (fp != NULLFILE)    {
  1627.         int thetype = -1;
  1628.  
  1629.         if ((cp = strrchr (rq->buf, '.')) != NULLCHAR)    {
  1630.             cp++;
  1631.             for (thetype = HTTPhtml; HTTPtypes[thetype].ext != NULLCHAR; thetype++) {
  1632.                 if (!strnicmp (HTTPtypes[thetype].ext, cp, strlen(HTTPtypes[thetype].ext)))
  1633.                     break;
  1634.             }
  1635.         }
  1636.         if (thetype == -1 || HTTPtypes[thetype].type1 == -1)
  1637.             /* either had no extension, or extension not found in table */
  1638.             thetype = (isbinary(fp)) ? HTTPbinary : HTTPplain;
  1639.  
  1640.         retval = 200;
  1641.         (void) fstat (fileno(fp), &sb);
  1642.         if (!head && rq->newcheck && !isnewer (sb.st_mtime, rq->newcheck))    {
  1643.             head = 1;
  1644.             retval = 304;
  1645.         }
  1646.  
  1647.         if (!strnicmp (newcommand, "bbs/user/", 9))
  1648.             rq->isvolatile = 1;
  1649.           httpHeaders (thetype, (retval == 304) ? "304 Not Modified" : "200 Document follows", rq, 1, NULLCHAR);
  1650.           httpFileinfo (fp, rq, thetype, version);
  1651.         if (!head)    {
  1652.             if (thetype != HTTPhtml && thetype != HTTPhtm)    {    /* if not html, just send */
  1653.                 tprintf ("\n");
  1654.                 (void) sendfile (fp, s, IMAGE_TYPE, 0);
  1655.             } else                /* otherwise, scan for server-side includes */
  1656.                 sendhtml (fp, 1, rq);
  1657.         }
  1658.         (void) fclose (fp);
  1659.     } else if (err) {
  1660.         retval = 404;
  1661.         httpHeaders (HTTPhtml, "404 Not Found", rq, 0, NULLCHAR);
  1662.         if (!head)
  1663.             tprintf ("<TITLE>Error</TITLE><H1>404 Not Found</H1>The file \"/%s\" does not exist on this server.\n", newcommand);
  1664.     }
  1665. quit0:
  1666.     free (tmp);
  1667.     openHTTPlog ("http");
  1668.     log (s, "port #%u: \"%s\" %d", port, command, retval);
  1669.     closeHTTPlog();
  1670.     (void) countusage ("tcount.dat", rq->dirname, 0, 1);
  1671.  
  1672. quit:
  1673.         usflush(Curproc->output);
  1674.     kpause (1000);
  1675.     close_s (Curproc->output);
  1676.  
  1677.     doPBBScmd_exit (rq);
  1678.     free (rq->url);
  1679.     free (rq->method);
  1680.     free (rq->version);
  1681.     free (rq->newcheck);
  1682.     free (rq->from);
  1683.     free (rq->referer);
  1684.     free (rq->agent);
  1685.     free (rq->passwd);
  1686.     free (rq->usetime);
  1687.     free (rq->useerror);
  1688.     free (rq->realm);
  1689.     free (rq->cookie);
  1690.     free (rq->rmtaddr);
  1691.     free (rq->rmthost);
  1692.     
  1693. #ifdef HTTPPBBS
  1694.     free (rq->areaname);
  1695.     free (rq->username);
  1696.     free (rq->bbspath);
  1697. #endif
  1698.     free (rq);
  1699.  
  1700.     HttpUsers--;
  1701.     HttpSessions--;
  1702.     ksignal (&HttpSessions, 1);
  1703.     kwait (NULL);
  1704. }
  1705.  
  1706.  
  1707.  
  1708. static char *
  1709. gmt_ptime (time_t *thetime)
  1710. {
  1711.     return ht_time(*thetime,HTTP_TIME_FORMAT, 1);
  1712. }
  1713.  
  1714.  
  1715.  
  1716. static char *
  1717. ht_time (time_t t, const char *fmt, int gmt)
  1718. {
  1719. static char ts[LINELEN];
  1720. struct tm *tms;
  1721.  
  1722.     tms = (gmt ? gmtime(&t) : localtime(&t));
  1723.  
  1724.     /* check return code? */
  1725.     (void) strftime (ts, LINELEN, fmt, tms);
  1726.     return ts;
  1727. }
  1728.  
  1729.  
  1730.  
  1731. static void
  1732. httpFileinfo (FILE *fp, struct reqInfo *rq, int thetype, char *vers)
  1733. {
  1734. struct stat sb;
  1735.  
  1736.     if (vers == NULLCHAR)
  1737.         return;        /* it is 0.9, no headers sent */
  1738.     if (!rq->isvolatile)
  1739.         if (fstat (fileno(fp), &sb) != -1)
  1740.             tprintf ("%s %s", HTTPHdrs[HDR_MODIFIED], gmt_ptime(&sb.st_mtime));
  1741.  
  1742.     if (thetype != HTTPhtml)
  1743.         tprintf ("%s %lu\n", HTTPHdrs[HDR_LENGTH], filelength(fileno(fp)));
  1744. }
  1745.  
  1746.  
  1747.  
  1748. static char *
  1749. assigncookie (struct reqInfo *rq, time_t thetime)
  1750. {
  1751. static char cookie[32];
  1752. char ipaddr[10], buf[32];
  1753. int i = SOCKSIZE;
  1754. struct sockaddr_in fsocket;
  1755. FILE *fp;
  1756. long nextCookie = 0;
  1757. int assignone = 1;
  1758. unsigned long address = INADDR_ANY;
  1759.  
  1760.     if (getpeername (rq->sock, (char *) &fsocket, &i) != -1)
  1761.         address = fsocket.sin_addr.s_addr;
  1762.  
  1763.     /* build ipaddress portion of cookie, which we'll also use to
  1764.        lookup this site, and see if there is already an assigned cookie */
  1765.     sprintf (ipaddr, "%02x%02x%02x%02x", (int) ((address >> 24) & 255),
  1766.         (int) ((address >> 16) & 255), (int) ((address >> 8) & 255),
  1767.         (int) (address & 255));
  1768.     
  1769.     /* get the next cookie number we should use, and build cookie
  1770.        string, in case we DO assign a new one */
  1771.     if ((fp = fopen (Cookiefile, READ_TEXT)) != NULLFILE)    {
  1772.         cookie[0] = 0;
  1773.         (void) fgets (cookie, 30, fp);
  1774.         nextCookie = atol (cookie);
  1775.         (void) fclose (fp);
  1776.     }
  1777.     sprintf (cookie, "%8.8s_%08ld_%012ld", ipaddr, ++nextCookie, thetime);
  1778.  
  1779.     /* look to see if there is already a cookie assigned to for this
  1780.        site. Browsers that do NOT support cookies could cause the
  1781.        Cookiedata file to grow to a large size, without this piece of code */
  1782.     if ((fp = fopen (Cookiedata, READ_TEXT)) != NULLFILE)    {
  1783.         while (fgets (buf, 32, fp) != NULLCHAR)    {
  1784.             if (!strncmp (buf, ipaddr, 8))    {
  1785.                 strncpy (cookie, buf, 32);
  1786.                 rip (cookie);
  1787.                 assignone = 0;
  1788.                 break;
  1789.             }
  1790.         }
  1791.         (void) fclose (fp);
  1792.     }
  1793.     
  1794.     
  1795.     if (assignone)    {    /* if we didn't find an old one, save this info */
  1796.         if ((fp = fopen (Cookiefile, WRITE_TEXT)) != NULLFILE)    {
  1797.             fprintf (fp, "%ld\n", nextCookie);
  1798.             (void) fclose (fp);
  1799.         } else    {
  1800.             /* if we can't save them, log an error, and disable creating more */
  1801.             log (-1, "Cannot write data to Cookiefile: '%s'", Cookiefile);
  1802.             HTTPusecookies = 0;
  1803.         }
  1804.  
  1805.         if ((fp = fopen (Cookiedata, APPEND_TEXT)) != NULLFILE)    {
  1806.             fprintf (fp, "%s\n", cookie);
  1807.             (void) fclose (fp);
  1808.         }
  1809.     }
  1810.  
  1811.     return (cookie);
  1812. }
  1813.  
  1814.  
  1815.  
  1816. static void
  1817. httpHeaders (int type, const char *str, struct reqInfo *rq, int more, const char *realm)
  1818. {
  1819. time_t thetime;
  1820.  
  1821.     if (rq->version == NULLCHAR)
  1822.         return;        /* it is 0.9, no headers sent */
  1823.     (void) time (&thetime);
  1824.     
  1825.     tprintf ("HTTP/1.0 %s\n%s %s", str, HTTPHdrs[HDR_DATE], gmt_ptime(&thetime));
  1826.     if (rq->isvolatile)
  1827.         tprintf ("%s %s", HTTPHdrs[HDR_EXPIRES], gmt_ptime(&thetime));
  1828.     if (realm)
  1829.         tprintf ("%s basic realm=\"%s\"\n", HTTPHdrs[HDR_AUTHENTICATE], realm);
  1830.     tprintf ("%s 1.0\n%s TNOS/"VERSION" "OS"\n", HTTPHdrs[HDR_MIME], HTTPHdrs[HDR_SERVER]);
  1831.     tprintf ("%s http://%s/%s\n", HTTPHdrs[HDR_LOCATION], rq->hostname, rq->url);
  1832.  
  1833.     if (HTTPusecookies && (rq->cookie == NULLCHAR || !strstr (rq->cookie, "TNOS=")))
  1834.         tprintf ("Set-Cookie: TNOS=%s; expires=%s; path=/; domain=%s\n",
  1835.             assigncookie (rq, thetime), ht_time (thetime + SECS_IN_6MONTHS, DEFAULT_TIME_FORMAT, 1), rq->hostname);
  1836.  
  1837.     tprintf ("%s %s%s\n", HTTPHdrs[HDR_TYPE], CTypes1[HTTPtypes[type].type1], HTTPtypes[type].type2);
  1838.  
  1839.     /* must have this line, when no more headers needed */
  1840.     if (more == 0)
  1841.         tputs ("\n");
  1842. }
  1843.  
  1844.  
  1845.  
  1846. static int
  1847. mkwelcome (const char *Hdir, char *file, int ftpfile, const char *Ftpdir)
  1848. {
  1849. char *dirstring,*p,*cp;
  1850. const char *ccp, *bitmap;
  1851. struct ffblk ffblk;
  1852. int done,pre = 0, k;
  1853. char *updir = NULLCHAR;
  1854. char *endstr;
  1855. int isadir;
  1856.  
  1857.     if ((dirstring = (char *)mallocw (strlen(file) + 16)) == NULL)
  1858.         return 0;
  1859.  
  1860.     strcpy (dirstring, file);
  1861.     (void) addFile (dirstring, Curproc->output);
  1862.  
  1863.     cp = strrchr (dirstring, '/');
  1864.     if (cp)
  1865.         *++cp = '\0';
  1866.     if (!ftpfile && strlen(Hdir) != strlen(dirstring))    {
  1867.         updir = strdup(&dirstring[strlen(Hdir)]);
  1868.         p = strrchr (updir, '/');
  1869.         if (p)
  1870.             *p = 0;
  1871.         p = strrchr (updir, '/');
  1872.         if (p == NULLCHAR)
  1873.             updir[0] = 0;
  1874.         else
  1875.             *++p = 0;
  1876.     } else if (ftpfile && strlen(Ftpdir) != strlen(dirstring))    {
  1877.         updir = strdup(&dirstring[strlen(Ftpdir)]);
  1878.         p = strrchr (updir, '/');
  1879.         if (p)
  1880.             *p = 0;
  1881.         p = strrchr (updir, '/');
  1882.         if (p == NULLCHAR)
  1883.             updir[0] = 0;
  1884.         else
  1885.             *++p = 0;
  1886.     }
  1887.     
  1888.     endstr = &dirstring[strlen(dirstring)];
  1889.  
  1890.     strcat (dirstring, HTTPheadfile);
  1891.     pre = addFile (dirstring, Curproc->output);
  1892.  
  1893.     strcpy (endstr, WILDCARD);
  1894.     done = findfirst (dirstring, &ffblk, (FA_HIDDEN|FA_SYSTEM|FA_DIREC));
  1895.     if (done)    {
  1896.         free (dirstring);
  1897.         return -1;
  1898.     }
  1899.     *endstr = 0;
  1900.     
  1901.     (void) sockmode (Curproc->output, SOCK_ASCII);
  1902.     (void) setflush (Curproc->output, -1); /* we will do our own flushing */
  1903.     p = dirstring + 1 + ((ftpfile) ? strlen(Ftpdir) : strlen(Hdir));
  1904.     if (ftpfile)    {
  1905.         p = (char *) mallocw (strlen (p) + 5);
  1906.         sprintf (p, "ftp/%s", dirstring + 1 + ((ftpfile) ? strlen(Ftpdir) : strlen(Hdir)));
  1907.     }
  1908.     undosify (p);
  1909.     if (!pre)
  1910.         tprintf ("<HEAD><TITLE>Index of /%s</TITLE></HEAD></BODY><H1>Index of /%s</H1>\n", p, p);
  1911.     tputs ("<PRE>\n");
  1912.  
  1913.     /* include the 'include' file, if it exists in this directory */
  1914.     strcpy (endstr, HTTPinclude);
  1915.     if (addFile (dirstring, Curproc->output))
  1916.         tputs ("<P>\n");
  1917.     *endstr = 0;
  1918.  
  1919.     tputs ("<IMG SRC=\"/icons/blank.xbm\" ALT=\"      \"> Name                   Last modified     Size\n<HR>\n");
  1920.     if (updir != NULLCHAR)    {
  1921.         if (*updir)
  1922.             tprintf ("<IMG SRC=\"/icons/menu.xbm\" ALT=\"[DIR ]\"> <A HREF=\"%s%s\">Parent Directory</a>\n", (ftpfile) ? "/ftp" : "", updir);
  1923.         free (updir);
  1924.     }
  1925.     while (!done) {
  1926.         isadir = 0;
  1927.  
  1928.         if (ffblk.ff_name[0] != '.')    {
  1929.             if (ffblk.ff_attrib & FA_DIREC)    {
  1930.                 ccp = "[DIR ]";
  1931.                 bitmap = "menu";
  1932.                 isadir = 1;
  1933.             } else {
  1934.                 ccp = "[FILE]";
  1935.                 bitmap = "text";
  1936.                 k = (int) (strlen(ffblk.ff_name) - 4);
  1937.                 if (k > 0 && (!strnicmp (&ffblk.ff_name[k], ".gif", 4) || !strnicmp (&ffblk.ff_name[k], ".jpg", 4) || !strnicmp (&ffblk.ff_name[k], ".xbm", 4)))
  1938.                     bitmap = "image";
  1939.             }
  1940.             tprintf (entry, bitmap, ccp);
  1941.             tprintf (entry1, p, ffblk.ff_name, (isadir) ? "/" : "", ffblk.ff_name);
  1942.             for (k = (int) strlen (ffblk.ff_name); k < 22; k++)
  1943.                 tputc (' ');
  1944.             tprintf (entry2,
  1945. #ifdef MSDOS
  1946.                 (ffblk.ff_fdate) & 0x1f,    /* day */
  1947.                 Months[((ffblk.ff_fdate >> 5) & 0xf)-1], /* month */
  1948.                 (ffblk.ff_fdate >> 9) + 80,    /* year */
  1949.                 (ffblk.ff_ftime >> 11) & 0x1f,    /* hour */
  1950.                 (ffblk.ff_ftime >> 5) & 0x3f,    /* minutes */
  1951. #else
  1952.                 ffblk.ff_ftime.tm_mday,        /* day */
  1953.                 Months[ffblk.ff_ftime.tm_mon],    /* month */
  1954.                 ffblk.ff_ftime.tm_year,        /* year */
  1955.                 ffblk.ff_ftime.tm_hour,        /* hour */
  1956.                 ffblk.ff_ftime.tm_min,        /* minute */
  1957. #endif
  1958.                 (int)((ffblk.ff_fsize + 1023L) / 1024L));
  1959.         }
  1960.         kwait (NULL);
  1961.         done = findnext (&ffblk);
  1962.     }
  1963.     tputs ("</PRE>\n");
  1964.     usflush (Curproc->output);
  1965.  
  1966.     strcat (dirstring, HTTPtailfile);
  1967.     if (!addFile (dirstring, Curproc->output))
  1968.         tputs ("</BODY>\n");
  1969.     free (dirstring);
  1970.     if (ftpfile)
  1971.         free (p);
  1972.     return 0;
  1973. }
  1974.  
  1975.  
  1976. extern FILE *Logfp;
  1977.  
  1978.  
  1979.  
  1980. static void
  1981. openHTTPlog (const char *name)
  1982. {
  1983. char filename[256];
  1984.  
  1985.     HTTPsavedfp = Logfp;
  1986.     sprintf (filename, "%s/%s.log", LOGdir, name);
  1987.     Logfp = fopen (filename, APPEND_TEXT);
  1988. }
  1989.  
  1990.  
  1991.  
  1992. static void
  1993. closeHTTPlog (void)
  1994. {
  1995.     if (Logfp != NULLFILE)
  1996.         (void) fclose (Logfp);
  1997.     Logfp = HTTPsavedfp;
  1998. }
  1999.  
  2000.  
  2001.  
  2002. static int
  2003. getmonth (char *cp)
  2004. {
  2005. int k;
  2006.  
  2007.     for (k = 0; k < 12; k++)    {
  2008.         if (!strnicmp (cp, Months[k], 3))    {
  2009.             return k;
  2010.         }
  2011.     }
  2012.     return 0;
  2013. }
  2014.  
  2015.  
  2016.  
  2017. static long
  2018. countusage (const char *file, const char *basedir, int display, int increase)
  2019. {
  2020. char name[256], buf[32];
  2021. FILE *fp;
  2022. long count = 0;
  2023.  
  2024.     sprintf (name,"%s/counts/%s", basedir, file);
  2025.     if ((fp = fopen (name, READ_TEXT)) != NULLFILE) {
  2026.         (void) fgets (buf, sizeof(buf), fp);
  2027.         (void) fclose (fp);
  2028.         count = atol (buf);
  2029.     }
  2030.     if (increase)    {
  2031.         count++;
  2032.         if ((fp = fopen (name, WRITE_TEXT)) != NULLFILE) {
  2033.             fprintf (fp, "%ld", count);
  2034.             (void) fclose (fp);
  2035.         }
  2036.     }
  2037.     if (display)
  2038.         tprintf ("%ld", count);
  2039.     return (count);
  2040. }
  2041.  
  2042.  
  2043.  
  2044. static int
  2045. isnewer (time_t thetime, char *tmstr)
  2046. {
  2047. time_t new;
  2048. struct tm t, *ltm;
  2049. char *cp, *cp2;
  2050. int format = 0;
  2051. time_t offset;
  2052.  
  2053.     /* the string should be in one of these three formats:
  2054.      * (a) RFC 822 (preferred) - Sun, 06 Nov 1994 08:49:37 GMT
  2055.      * (b) RFC 850           - Sunday, 06-Nov-94 08:49:37 GMT
  2056.      * (c) ANSI C's asctime    - Sun Nov  6 08:49:37 1994
  2057.      */
  2058.     /* skip past the name of the weekday */
  2059.     cp = skipwhite (tmstr);
  2060.     cp = skipnonwhite (cp);
  2061.     cp = skipwhite (cp);
  2062.     if (isdigit (*cp))    {    /* format a or b */
  2063.         cp[2] = 0;
  2064.         t.tm_mday = atoi (cp);
  2065.         cp += 3;
  2066.         t.tm_mon = getmonth (cp);
  2067.         cp += 4;
  2068.         cp2 = skipnonwhite (cp);
  2069.         *cp2 = 0;
  2070.         t.tm_year = atoi (cp);
  2071.         cp = ++cp2;
  2072.     } else {            /* format c */
  2073.         t.tm_mon = getmonth (cp);
  2074.         cp += 4;
  2075.         t.tm_mday = atoi (cp);
  2076.         cp += 3;
  2077.         format = 1;
  2078.     }
  2079.  
  2080.     /* time parsing is common between the three formats */
  2081.     sscanf (cp, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec);
  2082.     /* then parse the year, if format c */
  2083.     if (format) {
  2084.         cp += 9;
  2085.         t.tm_year = atoi (cp);
  2086.     }
  2087.     if (t.tm_year > 1900)
  2088.         t.tm_year -= 1900;
  2089. #ifdef HAVE_TM_ISDST
  2090.     t.tm_isdst = -1;
  2091. #endif
  2092.     new = mktime (&t);
  2093.     ltm = localtime(&new);        /* to get timezone info */
  2094. #if defined(HAVE_TM_ISDST) && !defined(MSDOS)
  2095.     offset = ((timezone - (ltm->tm_isdst * 3600L)) * -1);
  2096. #else
  2097.     offset = (ltm->tm_gmtoff * -1);
  2098. #endif
  2099.     new += offset;
  2100.     return (new != thetime);
  2101. }
  2102.  
  2103.  
  2104.  
  2105. static void
  2106. send_size (int sizefmt, long size)
  2107. {
  2108.     if (sizefmt == SIZEFMT_BYTES)    {
  2109.         tprintf ("%ld", size);
  2110.         return;
  2111.     }
  2112.     if (size == -1)
  2113.         tputs ("    -");
  2114.     else {
  2115.         if (!size)
  2116.             tputs ("   0K");
  2117.         else if (size < 1024)
  2118.             tputs ("   1K");
  2119.         else if (size < 1048576)
  2120.             tprintf ("%4ldK", size / 1024L);
  2121.         else
  2122.             tprintf ("%4ldM", size / 1048576L);
  2123.     }
  2124. }
  2125.  
  2126.  
  2127.  
  2128. #ifdef HTTPCGI
  2129. static void
  2130. setup_cgi_variables (struct reqInfo *rq, char *name)
  2131. {
  2132. char buf[80], *cp;
  2133. char *scriptname;
  2134.  
  2135.  
  2136.     if (name == NULLCHAR)
  2137.         scriptname = strdup (rq->url);
  2138.     else
  2139.         scriptname = name;
  2140.     (void) setenv ("GATEWAY_INTERFACE", "CGI/1.1", 0);
  2141.     (void) setenv ("SERVER_NAME", rq->hostname, 0);
  2142.     (void) setenv ("SERVER_SOFTWARE", "TNOS/"VERSION" "OS, 0);
  2143.     (void) setenv ("SERVER_PROTOCOL", "HTTP/1.0", 0);
  2144.     sprintf (buf, "%d", rq->port);
  2145.     (void) setenv ("SERVER_PORT", buf, 1);
  2146.     (void) setenv ("DOCUMENT_ROOT", rq->dirname, 1);
  2147.     (void) setenv ("REQUEST_METHOD", rq->method, 1);
  2148.     (void) setenv ("REMOTE_ADDR", (rq->rmtaddr) ? rq->rmtaddr : "", 1);
  2149.     (void) setenv ("REMOTE_HOST", (rq->rmthost) ? rq->rmthost : "", 1);
  2150.     (void) setenv ("SCRIPT_NAME", scriptname, 1);
  2151.     (void) setenv ("HTTP_REFERER", (rq->referer) ? rq->referer : "", 1);
  2152.     (void) setenv ("HTTP_USER_AGENT", (rq->agent) ? rq->agent : "", 1);
  2153.  
  2154.     if ((cp = strchr (scriptname, '?')) != NULLCHAR)    {
  2155.         *cp++ = 0;
  2156.         (void) setenv ("QUERY_STRING", cp, 1);
  2157.     } else
  2158.         (void) setenv ("QUERY_STRING", "", 1);
  2159.  
  2160.     sprintf (buf, "sysop@%s", rq->hostname);
  2161.     (void) setenv ("SERVER_ADMIN", buf, 0);
  2162.     
  2163.     /* not completely to spec */
  2164.     sprintf (buf, "%s/%s", rq->dirname, scriptname);
  2165.     (void) setenv ("SCRIPT_FILENAME", buf, 1);
  2166.  
  2167.     /* not supported, yet:
  2168.         PATH_INFO, PATH_TRANSLATED, AUTH_TYPE
  2169.         REMOTE_USER, REMOTE_IDENT, CONTENT_TYPE,
  2170.         CONTENT_LENGTH, HTTP_FROM, HTTP_ACCEPT
  2171.      */
  2172.  
  2173.     if (scriptname != name)
  2174.         free (scriptname);
  2175. }
  2176. #endif
  2177.  
  2178.  
  2179.  
  2180. static void
  2181. sendhtml (FILE *fp, int firstfile, struct reqInfo *rq)
  2182. {
  2183. time_t t;
  2184. struct stat ft;
  2185. char *cp, *cp1, *cp2, c;
  2186. char *remainder, *cmdname, newname[256];
  2187. FILE *tfp;
  2188. char *bufptr;
  2189. char buf[PLINELEN + 16];
  2190. int c2;
  2191. struct tag *tg;
  2192. int val;
  2193.  
  2194.  
  2195. #ifdef HTTPCGI
  2196.     setup_cgi_variables (rq, NULLCHAR);
  2197. #endif
  2198.     (void) sockmode (Curproc->output, SOCK_BINARY);
  2199.  
  2200.     if (firstfile)    {    /* if first file (not included file), search for meta tags */
  2201.             while ((c2 = fgetc (fp)) != EOF) {
  2202.             if (c2 == '<')    {
  2203.                 tg = parse_tag (fp);
  2204.                 if (tg != NULLTAG && !strcmp (tg->name, "meta"))    {
  2205.                     /* found a meta tag */
  2206.                     cp1 = find_option (tg, "http-equiv", NULL);
  2207.                     if (cp1 != NULLCHAR)    {
  2208.             
  2209.                         cp2 = find_option (tg, "content", NULL);
  2210.                         tprintf ("%s: %s\n", cp1, (cp2) ? cp2 : "");
  2211.                         free (cp1);
  2212.                         free (cp2);
  2213.                     }
  2214.                 }
  2215.                 delete_tag (tg);
  2216.             }
  2217.         }
  2218.         clearerr (fp);
  2219.         rewind (fp);
  2220.         tprintf ("\n");
  2221.     }
  2222.  
  2223.         while ((fgets (buf, PLINELEN + 15, fp)) != NULLCHAR) {
  2224.         kwait(NULL);
  2225.         bufptr = buf;
  2226.         while (bufptr  && (cp1 = strstr (bufptr, "<!--#")) != NULLCHAR) {
  2227.             if (cp1 != bufptr)    {
  2228.                 *cp1 = 0;
  2229.                 tputs (bufptr);
  2230.             }
  2231.             cp1 += 5;
  2232.             remainder = strstr (cp1, "-->");
  2233.             if (remainder != NULLCHAR) {
  2234.                 *remainder = 0;
  2235.                 remainder = &remainder[3];
  2236.             }
  2237.             cmdname = skipwhite (cp1);
  2238.             cp1 = skipnonwhite (cmdname);
  2239.             cp1 = skipwhite (cp1);
  2240.  
  2241.             if (!strnicmp (cmdname, "echo", 4)) {
  2242.                 if (!strnicmp (cp1, "var=\"", 5)) {
  2243.                     (void) time (&t);
  2244.                     cp1 += 5;
  2245.                     if ((cp2 = strrchr (cp1, '\"')) != NULLCHAR)
  2246.                         *cp2 = 0;
  2247.                     if (!stricmp (cp1, "DATE_LOCAL"))
  2248.                         tputs (ht_time (t, rq->usetime, 0));
  2249.                     else if (!stricmp (cp1, "DATE_GMT"))
  2250.                         tputs (ht_time (t, HTTP_TIME_FORMAT, 1));
  2251.                     else if (!stricmp (cp1, "HOSTNAME"))
  2252.                         tputs ((rq->hostname) ? rq->hostname : "unknownhost");
  2253.                     else if (!stricmp (cp1, "DOCUMENT_URI"))
  2254.                         tprintf ("/%s", rq->url);
  2255.                     else if (!stricmp (cp1, "VERSION"))
  2256.                         tputs (Version);
  2257. #ifdef HTTPPBBS
  2258.                     else if (!stricmp (cp1, "USERNAME"))
  2259.                         tputs ((rq->username) ? rq->username : "unknownUser");
  2260.                     else if (!stricmp (cp1, "AREANAME"))
  2261.                         tputs ((rq->areaname) ? rq->areaname : "unknownArea");
  2262.                     else if (!stricmp (cp1, "MESSAGECOUNT"))
  2263.                         tprintf ("%d", rq->msgcount);
  2264.                     else if (!stricmp (cp1, "NEWMSGCOUNT"))
  2265.                         tprintf ("%d", rq->newmsgcount);
  2266.                     else if (!stricmp (cp1, "CURMESSAGE"))
  2267.                         tprintf ("%d", rq->msgcurrent);
  2268.                     else if (!stricmp (cp1, "MESSAGENUM"))
  2269.                         tprintf ("%d", rq->msgnum);
  2270.                     else if (!stricmp (cp1, "PREV_MSGNUM"))
  2271.                         tprintf ("%d", rq->msgnum - 1);
  2272.                     else if (!stricmp (cp1, "NEXT_MSGNUM"))
  2273.                         tprintf ("%d", rq->msgnum + 1);
  2274.                     else if (!stricmp (cp1, "PERMISSIONS"))
  2275.                         doPBBScmd (rq, "security");
  2276.                     else if (!stricmp (cp1, "PREV_LIST_START"))
  2277.                         tprintf ("%d", (rq->msgnum > 100) ? rq->msgnum - 100 : 1);
  2278.                     else if (!stricmp (cp1, "NEXT_LIST_START"))
  2279.                         tprintf ("%d", rq->msgnum + 100);
  2280.                     else if (!stricmp (cp1, "PREV_LIST_BUTTON"))    {
  2281.                         if (rq->msgnum > 1)    {
  2282.                             sprintf (rq->buf, "%s/bbs/plbutton.cat", rq->dirname);
  2283.                             if ((tfp = fopen (rq->buf, "r")) != NULLFILE) {
  2284.                                 sendhtml (tfp, 0, rq);
  2285.                                 (void) fclose (tfp);
  2286.                             }
  2287.                         }
  2288.                     } else if (!stricmp (cp1, "PREV_MSG_BUTTON"))    {
  2289.                         if (rq->msgnum > 1)    {
  2290.                             sprintf (rq->buf, "%s/bbs/pmbutton.cat", rq->dirname);
  2291.                             if ((tfp = fopen (rq->buf, "r")) != NULLFILE) {
  2292.                                 sendhtml (tfp, 0, rq);
  2293.                                 (void) fclose (tfp);
  2294.                             }
  2295.                         }
  2296.                     } else if (!stricmp (cp1, "NEXT_MSG_BUTTON"))    {
  2297.                         if (rq->msgcount > rq->msgnum)    {
  2298.                             sprintf (rq->buf, "%s/bbs/nmbutton.cat", rq->dirname);
  2299.                             if ((tfp = fopen (rq->buf, "r")) != NULLFILE) {
  2300.                                 sendhtml (tfp, 0, rq);
  2301.                                 (void) fclose (tfp);
  2302.                             }
  2303.                         }
  2304.                     } else if (!stricmp (cp1, "NEXT_LIST_BUTTON"))    {
  2305.                         if (rq->msgcount > rq->msgnum + 100)    {
  2306.                             sprintf (rq->buf, "%s/bbs/nlbutton.cat", rq->dirname);
  2307.                             if ((tfp = fopen (rq->buf, "r")) != NULLFILE) {
  2308.                                 sendhtml (tfp, 0, rq);
  2309.                                 (void) fclose (tfp);
  2310.                             }
  2311.                         }
  2312.                     } else if (!stricmp (cp1, "AREA_LIST") || !stricmp (cp1, "AREA_MSG"))
  2313.                         doPBBScmd_term (rq);
  2314. #endif
  2315. #ifdef ALLSERV
  2316.                     else if (!stricmp (cp1, "QUOTE")) {
  2317.                         cp2 = getquote ();
  2318.                         tputs ((cp2) ? cp2 : "[quote not found]");
  2319.                     }
  2320. #endif
  2321.                     else if (!stricmp (cp1, "DOCUMENT_NAME"))    {
  2322.                         if (rq->url)    {
  2323.                             cp2 = strrchr (rq->url, '/');
  2324.                             if (cp2)
  2325.                                 cp2++;
  2326.                             else
  2327.                                 cp2 = rq->url;
  2328.                             tputs (cp2);
  2329.                         }
  2330.                     } else if (!stricmp (cp1, "LAST_MODIFIED")) {
  2331.                         (void) fstat (fileno(fp), &ft);
  2332.                         tputs (ht_time (ft.st_mtime, rq->usetime, 0));
  2333.                     } else if (!stricmp (cp1, "TOTAL_HIT_COUNT") || !stricmp (cp1, "TOTAL_HITS"))
  2334.                         (void) countusage ("tcount.dat", rq->dirname, 1, 0);
  2335.                     else if (!stricmp (cp1,"REQ_FROM")) {
  2336.                         if (rq->from)
  2337.                             tputs(rq->from);
  2338.                     } else if (!stricmp (cp1,"REQ_REFERER")) {
  2339.                         if (rq->referer)
  2340.                             tputs (rq->referer);
  2341.                     } else if (!stricmp (cp1,"REQ_AGENT")) {
  2342.                         if (rq->agent)
  2343.                             tputs (rq->agent);
  2344.                     } else if (!stricmp (cp1,"REQ_COOKIE")) {
  2345.                         if (rq->cookie)
  2346.                             tputs (rq->cookie);
  2347.                     } else if ((cp = getenv (cp1)) != NULLCHAR)
  2348.                         tputs (cp);
  2349.                     else
  2350.                         tputs (rq->useerror);
  2351.                 } else if (!strnicmp (cp1, "count=\"", 7) || !strnicmp (&cp1[1], "count=\"", 7))    {
  2352.                     c = (char) tolower(*cp1);
  2353.                     switch (c) {
  2354.                         case 'c':    /* count */
  2355.                         case 'i':    /* icount */
  2356.                         case 's':    /* scount */
  2357.                                 cp1 = strchr (cp1, '\"');
  2358.                                 if (cp1)    {
  2359.                                     cp2 = strrchr (++cp1, '\"');
  2360.                                     if (cp2)
  2361.                                         *cp2 = 0;
  2362.                                     (void) countusage (cp1, rq->dirname, (c != 's'), (c != 'c'));
  2363.                                 }
  2364.                                 break;
  2365.                         default:    tputs (rq->useerror);
  2366.  
  2367.                     }
  2368.                 } else
  2369.                     tputs (rq->useerror);
  2370.             } else if (!strnicmp (cmdname, "config", 6)) {
  2371.                 if (!strnicmp (cp1, "timefmt=\"", 9)) {
  2372.                     cp1 += 9;
  2373.                     if ((cp2 = strrchr (cp1, '\"')) != NULLCHAR)
  2374.                         *cp2 = 0;
  2375.                     free (rq->usetime);
  2376.                     rq->usetime = strdup (cp1);
  2377.                 } else if (!strnicmp (cp1, "sizefmt=\"", 9)) {
  2378.                     c = (char) tolower(cp1[9]);
  2379.                     /* either 'abbrev' or 'bytes' */
  2380.                     rq->sizefmt = (c == 'a') ? SIZEFMT_KMG : SIZEFMT_BYTES;
  2381.                 } else if (!strnicmp (cp1, "errmsg=\"", 8)) {
  2382.                     cp1 += 8;
  2383.                     if ((cp2 = strrchr (cp1, '\"')) != NULLCHAR)
  2384.                         *cp2 = 0;
  2385.                     free (rq->useerror);
  2386.                     rq->useerror = strdup (cp1);                    
  2387.                 } else
  2388.                     tputs (rq->useerror);
  2389.             } else if (!strnicmp (cmdname, "include", 7)) {
  2390.                 file_or_virtual (cp1, newname, rq);
  2391.                 if (*newname && (tfp = fopen (newname, "r")) != NULLFILE) {
  2392.                     sendhtml (tfp, 0, rq);
  2393.                     (void) fclose (tfp);
  2394.                 } else
  2395.                     tputs (rq->useerror);
  2396.             } else if (!strnicmp (cmdname, "fsize", 5)) {
  2397.                 file_or_virtual (cp1, newname, rq);
  2398.                 if (*newname)    {
  2399.                     (void) stat (newname, &ft);
  2400.                     send_size (rq->sizefmt, (long) ft.st_size);
  2401.                 } else
  2402.                     tputs (rq->useerror);
  2403.                         } else if (!strnicmp (cmdname, "flastmod", 8)) {
  2404.                 file_or_virtual (cp1, newname, rq);
  2405.                 if (*newname)    {
  2406.                     (void) stat (newname, &ft);
  2407.                     tputs (ht_time (ft.st_mtime, rq->usetime, 0));
  2408.                 } else
  2409.                     tputs (rq->useerror);
  2410. #if 0
  2411.             } else if (HTTPscript && !strnicmp (cmdname, "tscript", 7)) {
  2412.                 /* to be added later */
  2413.                 tputs (rq->useerror);
  2414. #endif
  2415.             } else if (!strnicmp (cmdname, "exec", 4))    {
  2416.                 /* exec cgi no supported, at least not yet */
  2417. #ifdef HTTPPBBS
  2418.                 if (HTTPexecbbs && !strnicmp (cp1, "bbs=\"", 5)) {
  2419.                     if ((cp2 = strrchr (cp1, '\"')) != NULLCHAR)
  2420.                         *cp2 = 0;
  2421.                     doPBBScmd (rq, &cp1[5]);
  2422.                 } else
  2423. #endif
  2424. #ifdef HTTPCGI
  2425.                 if (HTTPexeccgi && !strnicmp (cp1, "cgi=\"", 5)) {
  2426.                     if ((cp2 = strrchr (cp1, '\"')) != NULLCHAR)
  2427.                         *cp2 = 0;
  2428.                     if ((tfp = popen (&cp1[5], "r")) != NULLFILE) {
  2429.                         while ((val = fgetc (tfp)) != EOF)
  2430.                             tputc (uchar(val));
  2431.                     }
  2432.                     (void) pclose (tfp);
  2433.                 } else
  2434. #endif
  2435.                 if (HTTPexeccmd && !strnicmp (cp1, "cmd=\"", 5)) {
  2436.                     if ((cp2 = strrchr (cp1, '\"')) != NULLCHAR)
  2437.                         *cp2 = 0;
  2438.                     if ((tfp = popen (&cp1[5], "r")) != NULLFILE) {
  2439.                         while ((val = fgetc (tfp)) != EOF)
  2440.                             tputc (uchar(val));
  2441.                     }
  2442.                     (void) pclose (tfp);
  2443.                 } else
  2444.                     tputs (rq->useerror);
  2445.             } else {
  2446.                 tprintf ("<!--#%s-->", cmdname);
  2447.             }
  2448.             bufptr = remainder;
  2449.         }
  2450.         if (bufptr != NULLCHAR)
  2451.             tputs (bufptr);
  2452.     }
  2453. }
  2454.  
  2455.  
  2456.  
  2457. static void
  2458. file_or_virtual (char *cp, char *newname, struct reqInfo *rq)
  2459. {
  2460. char *cp2, *cp3;
  2461.  
  2462.     *newname = 0;
  2463.     if (!strnicmp (cp, "virtual=\"", 9))    {
  2464.         /* virtual filename, based on root http directory */
  2465.         cp2 = &cp[9];
  2466.         if (!strncmp (cp2, "../", 3) || !strncmp (cp2, "./", 2))
  2467.             cp2 = (strchr (cp2, '/') + 1);        /*lint !e613 * can't happen, see above line */
  2468.         sprintf (newname, "%s/%s", rq->dirname, cp2);
  2469.     } else if (!strnicmp (cp, "file=\"", 6)) {
  2470.         /* absolute filename */
  2471.         cp2 = &cp[6];
  2472.         if (!strncmp (cp2, "../", 3) || !strncmp (cp2, "./", 2))
  2473.             cp2 = (strchr (cp2, '/') + 1);        /*lint !e613 * can't happen, see above line */
  2474.         if (*cp2 == '/')
  2475.             cp2++;
  2476.         cp3 = strrchr (rq->url, '/');
  2477.         sprintf (newname, "%s%s/%s", rq->dirname, (cp3) ? cp3 : "", cp2);
  2478.     }
  2479.     if (*newname && (cp2 = strrchr (newname, '\"')) != NULLCHAR)
  2480.         *cp2 = 0;
  2481. }
  2482.  
  2483.  
  2484.  
  2485. static struct secureURL *
  2486. secured_url (struct reqInfo *rq)
  2487. {
  2488. struct secureURL *sec;
  2489.  
  2490.     /* lookup rq->url in securedURLS table, and return entry or NULL */
  2491.     for (sec = securedURLS; sec != NULLSECUREURL; sec = sec->next)    {
  2492.         /* 'http sec' url's ending in '/' protect entire directories */
  2493.         if (sec->url[strlen (sec->url) - 1] == '/')    {
  2494.             if (!strncmp (sec->url, rq->url, strlen (sec->url)))
  2495.                 return sec;
  2496.         } else if (!strcmp (sec->url, rq->url))    /* single protected URL */
  2497.             return sec;
  2498.     }
  2499.     return NULLSECUREURL;
  2500. }
  2501.  
  2502.  
  2503.  
  2504. static int
  2505. is_authorized (struct reqInfo *rq)
  2506. {
  2507. int retval = FALSE;
  2508. struct secureURL *sec;
  2509. char *tmp64 = NULLCHAR, *cp2;
  2510.  
  2511.     /* See if URL is secured, if not return TRUE */
  2512.     if ((sec = secured_url (rq)) == NULLSECUREURL)
  2513.         return TRUE;
  2514.         
  2515.     rq->realm = strdup (sec->realm);
  2516.     /* this URL is secured */
  2517.     if (rq->passwd != NULLCHAR)    {
  2518.         /* check the authentication, here */
  2519.         if (((tmp64 = base64ToStr(rq->passwd)) != NULLCHAR) && ((cp2 = strchr (tmp64, ':')) != NULLCHAR))    {
  2520.             *cp2++ = 0;
  2521.             retval = http_authcheck (sec->pwfile, tmp64, cp2);
  2522.         }
  2523.         free (tmp64);
  2524.     }
  2525.     return retval;
  2526. }
  2527.  
  2528.  
  2529.  
  2530. static int
  2531. http_authcheck (char *filename, char *username, char *pass)
  2532. {
  2533. char buf[80];
  2534. char *cp = NULLCHAR;
  2535. char *cp1;
  2536. FILE *fp;
  2537. int retval = FALSE;
  2538.  
  2539.     if ((fp = fopen (filename, "r")) == NULLFILE)    /* Authorization file doesn't exist */
  2540.         log (-1, "Authorization file %s not found\n", filename);
  2541.     else    {
  2542.         while ((void) fgets (buf, sizeof(buf), fp), !feof (fp)) {
  2543.             if (buf[0] == '#')
  2544.                 continue;    /* Comment */
  2545.  
  2546.             if ((cp = strchr (buf, ':')) == NULLCHAR)
  2547.                 continue;    /* Bogus entry */
  2548.  
  2549.             *cp++ = '\0';        /* Now points to password */
  2550.             if (strcmp (username, buf) == 0)    {
  2551.                 if ((cp1 = strchr (cp, ':')) == NULLCHAR)
  2552.                     break;
  2553.  
  2554.                 *cp1 = '\0';
  2555.                 if (strcmp (cp, pass) != 0)
  2556.                     break;    /* Password required, but wrong one given */
  2557.  
  2558.                 retval = TRUE;    /* whew! finally made it!! */
  2559.                 break;
  2560.             }
  2561.         }
  2562.         (void) fclose(fp);
  2563.     }
  2564.     return retval;
  2565. }
  2566.  
  2567. #endif /* HTTP */
  2568.  
  2569. #if defined(BROWSER) || defined(HTTP)
  2570.  
  2571. struct tag *
  2572. parse_tag (FILE *fp)
  2573. {
  2574. struct tag *tag;
  2575. struct options *opt;
  2576. int c, theindex = 0;
  2577. char buf[128];
  2578. int endquote;
  2579. int lookfor;
  2580.  
  2581.     tag = (struct tag *) callocw (1, sizeof (struct tag));
  2582.     c = fgetc (fp);
  2583.     if (c == '!')    {
  2584.         /* this is an HTML comment - whether we see the '--' or not */
  2585.         tag->name = strdup ("!--");
  2586.  
  2587.         /* eat the two '-'s */
  2588.         c = fgetc (fp);
  2589.         if (c != '-')    {    /* this covers !DOCTYPE tags */
  2590.             while (c != '>')
  2591.                 c = fgetc (fp);
  2592.             return tag;
  2593.         }
  2594.         c = fgetc (fp);
  2595.         for ( ; ; )    {
  2596.             c = fgetc (fp);
  2597.             while (!feof (fp) && c != '-')
  2598.                 c = fgetc (fp);
  2599.             if (feof (fp))
  2600.                 break;
  2601.             c = fgetc (fp);
  2602.             if (c != '-')
  2603.                 continue;
  2604.             c = fgetc (fp);
  2605.             while (!feof (fp) && c != '>')
  2606.                 c = fgetc (fp);
  2607.             break;
  2608.         }
  2609.         return tag;
  2610.     }
  2611.     if (c == '/')    {
  2612.         tag->endtag = 1;
  2613.         c = fgetc (fp);
  2614.     }
  2615.  
  2616.     while (!isspace (c) && c != '>')    {
  2617.         buf[theindex++] = (char) c;
  2618.         c = fgetc (fp);
  2619.     }
  2620.     buf[theindex] = 0;
  2621.     (void) strlwr (buf);
  2622.     tag->name = strdup (buf);
  2623.     while (c != '>')    {
  2624.         theindex = 0;
  2625.         opt = (struct options *) callocw (1, sizeof (struct options));
  2626.         opt->next = tag->opts;
  2627.         tag->opts = opt;
  2628.     
  2629.         c = fgetc (fp);
  2630.         while (!isspace (c) && c != '>' && c != '=')    {
  2631.             buf[theindex++] = (char) c;
  2632.             c = fgetc (fp);
  2633.         }
  2634.         buf[theindex] = 0;
  2635.         (void) strlwr (buf);
  2636.         opt->name = strdup(buf);
  2637.         if (c != '=')
  2638.             continue;
  2639.  
  2640.         theindex = 0;
  2641.         c = fgetc (fp);
  2642.         lookfor = ' ';
  2643.  
  2644.         if (c == '"')    {
  2645.             endquote = 1;
  2646.             lookfor = c;
  2647.             c = fgetc (fp);
  2648.         } else
  2649.             endquote = 0;
  2650.         while (c != lookfor)    {
  2651.             if (!endquote && ((c == '>') || isspace (c)))
  2652.                 break;
  2653.             buf[theindex++] = (char) c;
  2654.             c = fgetc (fp);
  2655.         }
  2656.         buf[theindex] = 0;
  2657.         rip (buf);        /* just in case */
  2658.         opt->value = strdup (buf);
  2659.     }
  2660.     return tag;
  2661. }
  2662.  
  2663.  
  2664.  
  2665. void
  2666. delete_tag (struct tag *tag)
  2667. {
  2668. struct options *opt, *last;
  2669.  
  2670.     if (tag == NULLTAG)
  2671.         return;
  2672.  
  2673.     free (tag->name);
  2674.     for (opt = tag->opts; opt != NULLOPTIONS; opt = last)    {
  2675.         free (opt->name);
  2676.         free (opt->value);
  2677.         last = opt->next;
  2678.         free (opt);
  2679.     }
  2680. }
  2681.  
  2682.  
  2683.  
  2684. char *
  2685. find_option (struct tag *tag, const char *str, int *found)
  2686. {
  2687. struct options *opt;
  2688.  
  2689.     if (found)
  2690.         *found = 0;
  2691.     for (opt = tag->opts; opt != NULLOPTIONS; opt = opt->next)    {
  2692.         if (!strcasecmp (str, opt->name))    {
  2693.             if (found)
  2694.                 *found = 1;
  2695.             return (opt->value) ? strdup (opt->value) : NULLCHAR;
  2696.         }
  2697.     }
  2698.     return NULLCHAR;    
  2699. }
  2700.  
  2701. #ifdef NO_SETENV
  2702. char *
  2703. setenv (char const *label, char const *value, int unused OPTIONAL)
  2704. {
  2705. char *temp;
  2706.  
  2707.     temp = (char *) mallocw (strlen (label) + strlen (value) + 2);
  2708.     sprintf (temp, "%s=%s", label, value);
  2709.     (void) putenv (temp);
  2710.     free (temp);
  2711.     return NULLCHAR;
  2712. }
  2713. #endif
  2714.  
  2715.  
  2716. #endif
  2717.  
  2718.